Electrical – Using Character Match functionality in a STM32F7 chip

dmainterruptsstm32stm32cubemxuart

I'm trying to implement a UART receiver that works by finding a '\0' in the datastream, OR when it receives 256 characters at which point the data should be processed by an interrupt. The point is to use DMA for reception but if either of these events occur it should stop filling up the current buffer and process the data. The reason is that I'm using COBS encoding to frame my data.

The STM32F7 chip has something called Character match as part of the Modbus specification, which I got working by setting the bits in the configuration register since it's not supported by the HAL(stm32cubemx, which would remove this code upon regenerating) libraries:

MODIFY_REG(huart->Instance->CR1, UART_CR1_FIELDS, tmpreg | USART_CR1_CMIE);

And at the end of the UART interrupt handler I do

UART8->ICR |= USART_ISR_CMF;

To clear the character match interrupt flag so it won't run again.

As I understand it the interrupt handlers in the STM32f7xx_it.c are in fact the first functions

void DMA1_Stream6_IRQHandler(void) and void UART8_IRQHandler(void)

in my case that are run as interrupts occur in a peripheral, and from these functions a handler(HAL_xxx_IRQHandler()) is run that check what interrupt occurred and run any user defined functions depending on the interrupt flags, like for example:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) {
    //process data, this runs when DMA finishes receiving bytes
}

The problem is that it's not clear which one of the interrupt function is ran when for example I'm using DMA and I have received my specified amount of data over UART. Does it run the UART interrupt or the DMA stream interrupt? How can I reliably end up in the same callback function on '\0'(uart?) or 256 bytes(dma?) to process my data without botching the interrupts?

Best Answer

The DMA CNDTR register counts down to zero after each transfer and shows how many elements remain to be trasferred. You can use it to check whether the DMA is running or not.

Your UART interrupts, if enabled, will always run alongside the DMA transfers and interrupts so the UART interrupts will have to chech the DMA's CNDTR register to know whether or not to actually execute.

You can also disable interrupts from within interrupts. So your DMA transfer complete interrupt can disable your character receive interrupt (or vice versa) and you can re-enable it elsewhere. Remember you also have interrupt priorities to handle when the last DMA transfer is "\0" character and triggers both the DMA transfer complete and character match interrupts at the same time.

In my code, I use character match to detect the enter key to know that a user command has been entered and to parse the message in memory being stored by the DMA. I also have a UART receive interrupt to echo characters that echoes the character directly from the UART receive register. These all run at the same time along with the DMA transfers and interrupts.