UART es de hecho bastante típico caso porque muchas aplicaciones que requieren algún procesamiento se realiza en respuesta al comando/fecha de recibido a través del puerto serie. Si la aplicación es architectured alrededor de un infinito bucle de procesamiento, como es a menudo el caso, una buena manera es utilizar DMA para la transferencia de bytes recibidos en un buffer pequeño y proceso de este búfer en cada iteración del bucle. El código de ejemplo siguiente ilustra esto:
#define BUFFER_SIZE 1000
uint8_t inputBuffer[BUFFER_SIZE];
uint16_t inputBufferPosition = 0;
// setup DMA reception USART2 RX => DMA1, Stream 6, Channel 4
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
DMA_InitTypeDef dmaInit;
DMA_StructInit(&dmaInit);
dmaInit.DMA_Channel = DMA_Channel_4;
dmaInit.DMA_PeripheralBaseAddr = ((uint32_t) USART2 + 0x04);
dmaInit.DMA_Memory0BaseAddr = (uint32_t) inputBuffer;
dmaInit.DMA_DIR = DMA_DIR_PeripheralToMemory;
dmaInit.DMA_BufferSize = BUFFER_SIZE;
dmaInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dmaInit.DMA_MemoryInc = DMA_MemoryInc_Enable;
dmaInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dmaInit.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dmaInit.DMA_Mode = DMA_Mode_Circular;
dmaInit.DMA_Priority = DMA_Priority_Medium;
dmaInit.DMA_FIFOMode = DMA_FIFOMode_Disable;
dmaInit.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dmaInit.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream5, &dmaInit);
USART_DMACmd(port, USART_DMAReq_Rx, ENABLE);
// loop infinitely
while(true)
{
// read out from the DMA buffer
uint16_t dataCounter = DMA_GetCurrDataCounter(DMA1_Stream5);
uint16_t bufferPos = BUFFER_SIZE - dataCounter;
// if we wrapped, we consume everything to the end of the buffer
if (bufferPos < inputBufferPosition)
{
while (inputBufferPosition < BUFFER_SIZE)
processByte(inputBuffer[inputBufferPosition++]);
inputBufferPosition = 0;
}
// consume the beginning of the buffer
while (inputBufferPosition < bufferPos)
processByte(inputBuffer[inputBufferPosition++]);
// do other things...
}
Lo que este código hace a la primera instalación de un canal de DMA para leer USART2. La correcta controlador de DMA, la corriente y el canal es la persona a cargo en el que USART utiliza (consulte el STM32 manual de referencia para averiguar qué combinación es necesaria para un determinado puerto USART). A continuación, el código entra en el principal bucle infinito. En cada bucle, el código comprueba si algo ha sido escrito (a través de la DMA) en inputBuffer
. Si es así, esta información es procesada por processByte
, que se debe implementar de una manera que es similar a la original IRQ controlador.
Lo bueno de esta configuración es que no hay ningún código de interrupción, todo lo que se ejecuta de forma sincrónica. Gracias a la DMA, los datos recibidos sólo "por arte de magia" aparece en inputBuffer
. El tamaño de inputBuffer
debe ser cuidadosamente determinada, aunque. Debe ser lo suficientemente grande para contener todos los datos que usted posiblemente puede recibir durante una iteración del bucle. Por ejemplo, con una tasa de 115200 baudios (sobre 11KB/s) y un máximo de bucle de tiempo de 50 ms, tamaño del buffer debe ser de al menos 11KB/s * 50 ms = 550 bytes.