STM32F4 Handling peripheral error while making a DMA Transfer (RX) - embedded

I am trying to communicate with the UART peripheral using DMA for both RX and TX.
I am using the HAL library that is supplied by ST (Generated with STCubeMX).
I am handling a UART channel with 1.5MBaud - so in order to not loose any data, I've configured the DMA in direct mode, with circular buffer, and handled the half-transfers interrupts to take care of the data, and keep the DMA online for more data to come.
The problem is that sometimes I can see in the Status Register of the UART that the Frame Error bit is on, and sometimes the Overrun Error flag is also on.
I can handle to lost bytes (using crc on the structured packets), but the problem is that the peripheral stops receiving data - but the DMA does not raise error, or stop the transfer.
So if I try to receive data, and the flag is on the system hangs.
I saw that the HAL provides a __weak function that should handle UART_Error, but it is never called - and the status in the HAL handle remains normal.
only a look at the register can tell that there is a problem.
How should I detect/handle these kind of errors?
Thanks

I do not use the HAL for performance reasons, as it is very clumsy and - imo also does not provide much abstraction to justify that. Handling the hardware directly is not much more complicated; even more as you still have to understand very well what goes on. And as you already detected, the HAL does only support a certain approach; once you follow your own trail, you are lost.
You apparently have similar issues as the overflow-flag is set. After such an error, you have to re-sync the receiver with the transmitter bytestream after an error in general. That would require out-of-band signalling using a symbol or line-condition not occuring within a packet. Framing errors are a good indicator there are problems to sync to the start of a symbol (start-bit) properly.
If the line is clean (not EMC problems), there should be no framing errors or data corruption (unless timing parameters do not match).
If using a simple ping-pong, a timeout might be sufficient. However, tha proper solution depends on the protocol. A good protocol design takes transmission errors and overflows into account.
Note that you have to enable receive-error interrupts in addition to DMA transfers to be informed. However, if you use a timeout (and a ping-pong protocol), you just can erase the flags, as the data did apparently not arrive in-time. If actually using error-interrupts be aware of race-conditions, too.

Related

How to get data from an interrupt into a task-based system?

I am preparing for an embedded systems interview and was given this question as one of the questions to prepare with.
From my research, I learned that interrupts are called by a piece of hardware when there is an important issue that the OS should take care of and because of this data cannot be returned by an interrupt.
However, I didn't find any definitive information about how interrupts work with a task-based system. Is this a trick question about interrupts or is there a method to get data from them?
It is true that an interrupt cannot "return" data to a caller, because there is no caller. Interrupts are triggered by asynchronous events independent of normal program flow.
However it is possible for an interrupt pass data to a thread/task context (or even other interrupts) via shared memory or inter-process communication (IPC) such as a message queue, pipe or mailbox. Such data exchange must be non-blocking. So for example, if a message queue is full, the ISR may not wait on the queue to become available - it must baulk and discard the data.
interrupts are called [...] when there is an important issue that the OS should take care of [...]
It is not about "importance" it is about timliness, determinusm, meeting real-time deadlines, and dealing with data before buffers or FIFOs are overrun for example. There need not even be an OS, ant interrupts are generally application specific and not an issue for the OS at all.
I didn't find any definitive information about how interrupts work with a task-based system.
Perhaps you need to hone your research technique (or Google Fu). https://www.google.com/search?q=rtos+interrupt+communication
It's not a trick question. The problem is the same whether you have a "task-based system" (RTOS) or not:
Interrupts will happen at random times, relative to your main program. I.e. you could be calculating something like a = b + c and the interrupt could happen at a time where b is loaded into a register, but before c is.
Interrupts execute in a different context from your main program. Depending on the architecture, you could have a separate stack, for example.
Given the above, the interrupt service routines cannot take any parameters and cannot return any values. The way to pass data in and out of an ISR is to use shared memory (e.g. a global variable).
There are several ways to get data from interrupt:
Using queue or similar approach (implement in freeRTOS). NOTE: there is special API for ISR.
Using global variable. For this way you need to care about consistency of data because interrupt can happen anytime.
...

Will semaphore corrupt data transmission of peripherals like UART in a microcontroller?

Semaphore disables interrupts and so will this cause other operations like receiving data on SPI to get corrupt?
Disabling interrupts cannot corrupt the data on the hardware interface.
The problem is if the data is received by the hardware peripheral and then the it raises an interrupt to have the processor collect the data then this will be delayed. If it is delayed for too long then potentially more data will have been received. Depending on the peripheral, either the new data or the old data will have to be discarded. Either way stream of data will be incomplete.
In most cases it is difficult to predict or test how long it is safe to disable interrupts for, so if possible it is best to avoid turning interrupts off.
If the peripheral includes a FIFO buffer, then the length of time that it is safe to disable interrupts for may be increased (although still difficult to predict).
Most modern microcontrollers have many ways to avoid disabling interrupts:
A better approach is to have the peripheral transfer the data to memory with DMA, so no interrupt is required at all.
Most modern processor cores provide ways to implement a semaphore do not even need to disable interrupts.
There's no standard way of implementing a semaphore. To disable all interrupts on the MCU is one way to do it, but it's a very poor amateur way of doing so. Because in more complex applications with multiple interrupts, this will make all real-time considerations and calculations a nightmare.
It creates subtle but severe bugs. Particularly when some quack has done so from deep inside some driver code. You import the driver into your project and suddenly previously working code breaks. In particular, be very careful about using various libs provided by silicon vendors - they are often of very poor quality.
There are better ways to do it, including:
Ensuring atomic access of shared variables, which can only be done with inline assembler or C11 _Atomic if supported.
Disabling one specific interrupt for a specific hardware peripheral, if it is possible to do do given the real-time considerations. Then this should be handled by the driver for that hardware peripheral in the form of setter/getter functions.
Use a "poor man's semaphore" in the form of a plain flag variable, by relying on the interrupt mechanism of the MCU blocking all other interrupts while the ISR is executing. Example.

What is the difference between Synchronous and asynchronous I2C in embedded programming?

What is the difference between Synchronous and asynchronous I2C in embedded programming? Could anyone explain this using an example? When to use either of them?
I2C is a synchronous protocol, meaning that the communicating parties do not need to agree to a certain speed beforehand - think at the asynchronous serial lines like RS-232, where no communication can succeed if the parties don't use the same baud rate.
The sync/async someone refers to, speaking of i2c, it's in another level, we may call it API. A synchronous API (or routine) will start the communication and will not return control to the program until the whole data will be sent or received. The time taken to do the transfer will be unavailable for the program.
If the communication is asynchronous, the calling program can invoke the i2c driver and then continue to do its work. Later, the program should be notified (or the program should check) about the result of the transaction: "is the writing/reading still in progress?"; and if it is terminated, did it go well or not?
Sync/async in the context of i2c can be thought the same as disk (file) I/O: often synchronous disk access is used, which is simple and effective: read some data in memory, check if the reading was ok, do something with the data, and go ahead. In the asynchronous way, the program says something like "I need those data: I/O driver, please fetch them while I do something else; when the data will be available I will do something with that".
The asynchronous mode for i2c can be pleasant especially because i2c is slow when compared to other ways to exchange data. On the other hand, i2c is used for little data, certainly not for a hard disk!
Speaking strictly about the embedded world, often the MCU has to do many things concurrently, and an i2c device can be simply slow enough to make the MCU lose too much time if the i2c is bit-banged. But often there is hardware support, interrupt-driven. Anyway, a non-blocking (i.e. asynchronous) API is more difficult to manage.
-- UPDATE AFTER COMMENT --
"often there is hardware support, interrupt-driven. Anyway, a non-blocking (i.e. asynchronous) API is more difficult to manage" Do you mean the implementation of synchronus I2C in a multimodal sensor system can be easier than the other and still give similar performance.
Let's assume there is an asynchronous hardware+driver support: we call
i2c_write(periph_addr, data_to_send[], 6);
// send 6 bytes to the peripheral
After few microseconds the routine returns, but the communication is still ongoing. At this point we can not issue another i2c_write(...), because we would interrupt the ongoing one. The program could do something else, yes, but not use the same bus. And if instead i2c_write(...) we used a
i2c_read(...);
we would have not the data ready when the routine returns: the program must use i2c_read(), but use the data only later, when arrived, and without touching the i2c bus in the meanwhile. Not difficult to do, but surely a synchronous call/API like:
if ( i2c_read(some_data) == I2COK)
display(some_data);
else display(error);
is far simpler.

DSPIC33F UART DMA Example not working

I am trying to use DMA for my UART Rx and Tx. Till now I had the freeRTOS version of the serial demo working fine. It still works fine. However, now I have incorporated the UART DMA example, from the example projects.
the code is conditionally compiled, so that when a switch _HAS_DMA == 1, only then the DMA engine is configured, ram buffers are configured, and default UART ISRs as required by the FreeRTOS demo are removed.
At this point, whenever I send a serial byte stream, the running project simply gets reset.
I am using MPLAB IDE 8.92, XC16 v1.20, Explorer-16 platform, dspic33fj256gp710 part.
The DMA code included does not use any FreeRTOS API calls.
I have setup the project so that StackOverflow is detected using the FreeRTOS configuration option. But the code does not reach the Stackoverflow hook function. I have also included the U2ErrInterrupt ISR to see if incoming bytes are coming in fine, however even that interrupt is not reached.
Has any one faced this before?
interestingly, the UART DMA Loopback example from Microchip website, which uses the MPLAB C30 compiler, works fine on my board.
any pointers on this one? I could not locate any code examples in the FreeRTOS forum on how to use the DMA for UART, but it is suggested to use this method in production code for efficiency.
Need help here.
Thanks and best regards,
Vishal
OK. I found the culprit. Its me. :)).
When setting up the DMA to receive UART interrupts, one should not enable UART interrupt separately in software. Which is what I was doing. In addition, I had conditionally un-compiled the UART ISRs from my code !!!. So in effect, whenever a byte was received by the UART engine, the processor is getting confused as to who will serve this interrupt, DMA or Application code. I thing the PC would point to the designated UART RX ISR vector location, where the processor would not find anything, and this was causing the reset. Or may be there was a race condition setup between the DMA and the processor to serve this interrupt, which was causing the reset.
Now that I have setup UART so that Interrupts are not enabled separately by application, when DMA is going to serve the UART RX, my code is working fine. I am yet to integrate the whole thing with FreeRTOS deferred interrupt processing using binary semaphores, but I hope I will not see any troubles there.
There is not much documented about this though...neither in Microchip manuals nor in the FreeRTOS examples.
Also, I found that when using DMA with UART, as per the manual, the DMA receives WORDS from the UART RX engine, with lower byte having the data, and upper byte having the status. If the DMA is also used for UART Tx, and is set to transfer WORDS to UART TXREG, the two intelligently manage to send only the lower data byte out. So the receiving party still gets expected bytes. This is also not documented well.
I will try to post my code here for future generations though :)).

Which Cortex-M3 interrupts can I use for general purpose work?

I'd have some code that needs to be run as the result of a particular interrupt going off.
I don't want to execute it in the context of the interrupt itself but I also don't want it to execute in thread mode.
I would like to run it at a priority that's lower than the high level interrupt that precipitated its running but also a priority that higher than thread level (and some other interrupts as well).
I think I need to use one of the other interrupt handlers.
Which ones are the best to use and what the best way to invoke them?
At the moment I'm planning on just using the interrupt handlers for some peripherals that I'm not using and invoking them by setting bits directly through the NVIC but I was hoping there's a better, more official way.
Thanks,
ARM Cortex supports a very special kind of exception called PendSV. It seems that you could use this exception exactly to do your work. Virtually all preemptive RTOSes for ARM Cortex use PendSV to implement the context switch.
To make it work, you need to prioritize PendSV low (write 0xFF to the PRI_14 register in the NVIC). You should also prioritize all IRQs above the PendSV (write lower numbers in the respective priority registers in the NVIC). When you are ready to process the whole message, trigger the PendSV from the high-priority ISR:
*((uint32_t volatile *)0xE000ED04) = 0x10000000; // trigger PendSV
The ARM Cortex CPU will then finish your ISR and all other ISRs that possibly were preempted by it, and eventually it will tail-chain to the PendSV exception. This is where your code for parsing the message should be.
Please note that PendSV could be preempted by other ISRs. This is all fine, but you need to obviously remember to protect all shared resources by a critical section of code (briefly disabling and enabling interrupts). In ARM Cortex, you disable interrupts by executing __asm("cpsid i") and you enable interrupts by __asm("cpsie i"). (Most C compilers provide built-in intrinsic functions or macros for this purpose.)
Are you using an RTOS? Generally this type of thing would be handled by having a high priority thread that gets signaled to do some work by the interrupt.
If you're not using an RTOS, you only have a few tasks, and the work being kicked off by the interrupt isn't too resource intensive, it might be simplest having your high priority work done in the context of the interrupt handler. If those conditions don't hold, then implementing what you're talking about would be the start of a basic multitasking OS itself. That can be an interesting project in its own right, but if you're looking to just get work done, you might want to consider a simple RTOS.
Since you mentioned some specifics about the work you're doing, here's an overview of how I've handled a similar problem in the past:
For handling received data over a UART one method that I've used when dealing with a simpler system that doesn't have full support for tasking (ie., the tasks are round-robined i na simple while loop) is to have a shared queue for data that's received from the UART. When a UART interrupt fires, the data is read from the UART's RDR (Receive Data Register) and placed in the queue. The trick to deal with this in such a way that the queue pointers aren't corrupted is to carefully make the queue pointers volatile, and make certain that only the interrupt handler modifies the tail pointer and that only the 'foreground' task that's reading data off the queue modified the head pointer. A high-level overview:
producer (the UART interrupt handler):
read queue.head and queue.tail into locals;
increment the local tail pointer (not the actual queue.tail pointer). Wrap it to the start of the queue buffer if you've incremented past the end of the queue's buffer.
compare local.tail and local.head - if they're equal, the queue is full, and you'll have to do whatever error handing is appropriate.
otherwise you can write the new data to where local.tail points
only now can you set queue.tail == local.tail
return from the interrupt (or handle other UART related tasks, if appropriate, like reading from a transmit queue)
consumer (the foreground 'task')
read queue.head and queue.tail into locals;
if local.head == local.tail the queue is empty; return to let the next task do some work
read the byte pointed to by local.head
increment local.head and wrap it if necessary;
set queue.head = local.head
goto step 1
Make sure that queue.head and queue.tail are volatile (or write these bits in assembly) to make sure there are no sequencing issues.
Now just make sure that your UART received data queue is large enough that it'll hold all the bytes that could be received before the foreground task gets a chance to run. The foreground task needs to pull the data off the queue into it's own buffers to build up the messages to give to the 'message processor' task.
What you are asking for is pretty straightforward on the Cortex-M3. You need to enable the STIR register so you can trigger the low priority ISR with software. When the high-priority ISR gets done with the critical stuff, it just triggers the low priority interrupt and exits. The NVIC will then tail-chain to the low-priority handler, if there is nothing more important going on.
The "more official way" or rather the conventional method is to use a priority based preemptive multi-tasking scheduler and the 'deferred interrupt handler' pattern.
Check your processor documentation. Some processors will interrupt if you write the bit that you normally have to clear inside the interrupt. I am presently using a SiLabs c8051F344 and in the spec sheet section 9.3.1:
"Software can simulate an interrupt by setting any interrupt-pending flag to logic 1. If interrupts are enabled for the flag, an interrupt request will be generated and the CPU will vector to the ISR address associated with the interrupt-pending flag."