Page 1 of 1

SOLVED: UART not firing interrupt on real hardware

Posted: Sun Jun 15, 2014 6:05 pm
by BASICFreak
This is working well on bochs but on real H/W I get nothing.
I can send and receive on hardware (if not relying on IRQ)
I narrowed down my UART model to a 16550A.

Here is my Init Code

Code: Select all

void setBaudRate(uint16_t COM, uint32_t RATE)
{
	uint8_t LO_RATE, HI_RATE;
	
	LO_RATE = (uint8_t) ((115200 / RATE) & 0xFF);
	HI_RATE = (uint8_t) ((115200 / RATE) >> 8);
	
	IER_handle(COM, false, false, false, false);							//Disable IRQ
	write(COM, FCR, (FCR_ClearRX | FCR_ClearTX));							//Disable FIFO
	write(COM, LCR, LCR_DLAB);												//DLAB
	write(COM, DLL, LO_RATE);												//Data Rate Low
	write(COM, DLH, HI_RATE);												//Data Rate High
	write(COM, LCR, LCR_8Bits);												//Line Control
	write(COM, FCR,(FCR_Enable | FCR_ClearRX | FCR_ClearTX | FCR_16_1));	//Enable FIFO - 1 BYTE BUFFER NOTIFY
	write(COM, MCR, (MCR_DataTermRdy | MCR_RequestSend | MCR_AuxOut2));
	IER_handle(COM, true, true, true, true);								
}
Which breaks down to (assuming 3F8 Base COM1)

Code: Select all

outb(0x3F9, 0);
outb(0x3FA, 6);
outb(0x3FB, 0x80);
outb(0x3F8, 1);    //DATA RATE = 115200
outb(0x3F9, 0);
outb(0x3FB, 3);
outb(0x3FA, 7);
outb(0x3FC, 0xB);
outb(0x3F9, 0xF);    //ENABLE ALL INT
Currently I have debug information coming out COM1 and I really need input so I can modify and FIX my 8042 drivers (which as you all know will disable my keyboard)

If you need more information ask or check the link in signature (DRIVERSRC/HARDWARE/RS232.C\H)

I've been comparing to many others on the forum and I cannot, as of yet, find what is wrong.

Re: UART not firing interrupt on real hardware

Posted: Thu Jun 19, 2014 12:15 pm
by BASICFreak
Well, if anyone is interested I believe my problem is faulty hardware, as a second test system worked with flying colors... I will still continue to look and see if maybe I missed something important before I claim 100% H/W issue.

Re: UART not firing interrupt on real hardware

Posted: Thu Jun 19, 2014 11:12 pm
by ChosenOreo
Just to be on the safe side I would make sure that 0x3f8 is actually your serial port, as I have heard of a few systems (don't have any sources, sorry!) that don't actually use 0x3f8 as the first serial port. However, I'm pretty sure that the port number can be found at physical address 0x400, which is located in the BDA.

- Adrian

Re: UART not firing interrupt on real hardware

Posted: Fri Jun 20, 2014 9:05 am
by BASICFreak
ChosenOreo wrote:Just to be on the safe side I would make sure that 0x3f8 is actually your serial port, as I have heard of a few systems (don't have any sources, sorry!) that don't actually use 0x3f8 as the first serial port. However, I'm pretty sure that the port number can be found at physical address 0x400, which is located in the BDA.

- Adrian
Don't Worry about this :D (I have a BIOS probe which gives me all the info on COM LPT etc.)

Code: Select all

COM1 = _BIOS_COM(1);
COM2 = _BIOS_COM(2);
COM3 = _BIOS_COM(3);
COM4 = _BIOS_COM(4);
Which on this system in particular is 3F8 COM1 and 2F8 COM2 COM3&4 don't exist

Now, if only I can find an IDE CD drive to live boot ubuntu and really test the COM port...

Re: UART not firing interrupt on real hardware

Posted: Sat Jun 21, 2014 3:49 am
by gerryg400
Hi. I'm not sure what your bug is, it may be hardware, however the order that you initialise things may cause you problems.
Generally speaking the order should be more like this:

Code: Select all

1. Disable all interrupts on device
2. Initialise device (set baud rate etc.)
3. Clear (or acknowledge) pending interrupts on device
4. Install interrupts handler
5. Enable interrupts on device.
If you don't do things in this order you can miss an interrupt, permanently.
This same sequence applies to other devices too.

I had a quick look at your code. It doesn't seem to follow these steps. In particular I couldn't see where you acknowledged potentially pending interrupts.

SOLVED: UART not firing interrupt on real hardware

Posted: Sun Jun 22, 2014 6:43 am
by BASICFreak
Well, after finally thinking to look at Linux 0.96c Source #-o on the manner I changed my init routine to the following:

Code: Select all

uint8_t LO_RATE, HI_RATE;
	
LO_RATE = (uint8_t) ((115200 / RATE) & 0xFF);
HI_RATE = (uint8_t) ((115200 / RATE) >> 8);
	
IER_handle(COM, false, false, false, false);							//Disable IRQ
write(COM, FCR, (FCR_ClearRX | FCR_ClearTX));							//Disable FIFO
write(COM, LCR, LCR_DLAB);												//DLAB
write(COM, DLL, LO_RATE);												//Data Rate Low
write(COM, DLH, HI_RATE);												//Data Rate High
write(COM, LCR, LCR_8Bits);												//Line Control
write(COM, FCR,(FCR_Enable | FCR_ClearRX | FCR_ClearTX | FCR_16_1));	//Enable FIFO - 1 BIT BUFFER NOTIFY
write(COM, MCR, (MCR_DataTermRdy | MCR_RequestSend | MCR_AuxOut2));
IER_handle(COM, true, false, false, false);								//Enable IRQ for RX only
(void) read(COM, RBR);	//read to clear things up? - linux 0.96c code idea (seemed to fix my irq issues)
Which I just added a (void) inb(3f8);
Now I have a very stable Driver, I managed to crash the Kernel and was still getting the echos back :D

@gerryg400
I clear Tx and Rx buffer what else should I do here?




Off-Topic:
I have finally switch back to a cross compiler on a lubuntu (virtual) PC fixed about 2000 warnings I was not getting with DJGPP, compiling to ELF32-i386, and unfortunately using Grub 0.92 (not that Grub is bad just I need to work on my boot code now)

In the process I broke my Phys Mem Manager, and lost my FDC (is unstable and I knew Grub would break it) So I disabled my physical and virtual mem managers, thread manager, FDC driver, and FAT12 driver... (hopefully I'll get everything back up and I'll upload to repo soon)

But on the plus side I now have a steady I/O source which is logged and can test, debug, and build drivers live (well at least the first 2)
AND FINALLY A WORKING MAKEFILE!!!!

Re: SOLVED: UART not firing interrupt on real hardware

Posted: Sun Jun 22, 2014 7:27 am
by gerryg400
@gerryg400
I clear Tx and Rx buffer what else should I do here?
Hi. I'm glad you got it working.

To make your driver bullet proof you should

1. Disable all interrupts on the device. You already do this with IER_handle(COM, false, false, false, false);

2. Read the IIR and acknowledge all pending interrupts until the IIR == 1
You already the read the RBR to clear an RX interrupt, but there may be others. In fact I'm not sure but I think that reading the RBR may only clear the RX interrupt if that is the highest pending interrupt. Not 100% sure about that. Never tried it.

3. Install a handler routine so that if another interrupt occurs you can handle it.

4. Enable Interrupts in the device.