Hi all. I'm writing an experimental and custom driver layer for the Tiva-C platform (TM4C1294) in Code Composer using C++. I've been having great success writing GPIO, Clock and NVIC drivers but have run into a strange behavior in the UART that I can't seem to work out. I've done all the obvious checks and have run out of theories. I'm merely looking for ideas and possible failure paths to investigate.
Please note that this this is not with CMSIS and that's the goal of this project.
Here is the breakdown of what I'm experiencing:
- I have a UART driver that uses the peripheral in character mode (no FIFO) and a giant circular/ring buffer for transmission and reception.
- My setup follows a similar initialization scheme to what the CMSIS code performs. I just do it in registers directly.
- Things are working beautifully here thus far. I can send and receive data without any problem except in the following circumstance.
- When the transmit buffer is full, I want the code to block until space opens up in the buffer.
- To do this, I have a while loop which breaks only when the number of buffered bytes is less than the size of the queue. Nothing magical here.
- Whenever this condition occurs and it must wait, the code will hang and when I pause the debugger, the instruction pointer is at 0x00000000.
- As long as this condition isn't met, the code will happily run without problems, but once it starts looping, horrible things happen.
Additionally:
- The buffer is implemented fully in software, using the classic insertion/extraction offsets approach. I track the number of bytes buffered using a separate variable rather than checking insert==extract conditions. More data but cleaner.
- I try to write as stable drivers as possible and have checks for overrun/underrun conditions, as well as performing modulo-division on every offset prior to use. There are no access violations going on here.
- I've confirmed the UART driver setup against the register setup: there is no discrepancy between what the driver wishes to configure and what the registers are setup as.
- All configuration changes are performed when the UART is disabled and remain unchanged whenever the UART is enabled. (UARTCTL enable)
- The potential infinite loop isn't the problem. I've done a flat while( true) {} instruction and it'll happily loop there without any problems.
There are only two potential problems I can foresee, both are esoteric and (I think) highly unlikely.
- The UART driver uses OOP and simple inheritance, and checks two properties of the instance. By necessity therefore, the ISR must access these as well. Could there be something in how CCS handles OOP that cannot be performed properly in the ISR. But if that's the case, this would have showed up regardless of the full condition being met. The problematic code is here:
// If the transmit buffer is full, wait for space to open up while( this->bTxBufferWaiting >= this->bTxBufferSize) {}
- Because the property "this->bTxBufferWaiting" is modified inside the ISR, could their be some sort of access violation between the loop and the ISR? I don't see how this would be a problem, it's not like these operations are multi-instruction and this sort of thing must be mediated by the processor during context switch anyway. Not to mention the fact that this would be the sort of thing the fault ISRs would pick up.
I can release portions of code if requested, I'd prefer not to merely because this is part of a larger driver layer experiment and thus would be a ton of code for you all to sift through. I'm content to explore any angle presented here. I'm just flat out of ideas to investigate.
Thanks all.