USART2 DMA RX/TX works
- Rx/Tx handler in usart2_dma.* - CubeMX: USART and DMA init - DMA CH2: Tx - DMA CH3: Rx - DMA Port0 for periph transfer - DMA Port1 for mem transfer - Continuous Rx handling via DMA pointer (no INT, no TC flag) - Tx: collect data into tx buf or send immediatelymaster
parent
b8802c266f
commit
9b1029a5e1
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef __USART2_IT_H__
|
||||||
|
#define __USART2_IT_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "usart2_dma_cfg.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern uint8_t Usart2RxDmaBuf[USART2_RXDMA_BUF_SIZE];
|
||||||
|
|
||||||
|
extern void Usart2_DMA_Init(void (*)(const uint8_t* data, uint16_t len));
|
||||||
|
extern void Usart2_DMA_Task();
|
||||||
|
extern uint8_t Usart2_TxBufWrite(const void* src, size_t n, uint8_t flush);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __USART2_IT_CFG_H__
|
||||||
|
#define __USART2_IT_CFG_H__
|
||||||
|
|
||||||
|
#include "stm32h5xx_ll_dma.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define USART2_RXDMA_BUF_SIZE 2048
|
||||||
|
#define USART2_TXDMA_BUF_SIZE 2048
|
||||||
|
|
||||||
|
#define USART2_GPDMA GPDMA1
|
||||||
|
#define USART2_DMA_TX_CHANNEL LL_DMA_CHANNEL_2
|
||||||
|
#define USART2_DMA_RX_CHANNEL LL_DMA_CHANNEL_3
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __USART2_CFG_H__
|
||||||
@ -0,0 +1,238 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file usart2_dma.c
|
||||||
|
* @brief UART with DMA
|
||||||
|
*//****************************************************************************/
|
||||||
|
|
||||||
|
//------------------------------C library---------------------------------------
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
//----------------------------user includes-------------------------------------
|
||||||
|
#include "usart2_dma.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Private typedefs ----------------------------------------------------------*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t BufA[USART2_TXDMA_BUF_SIZE];
|
||||||
|
uint8_t BufB[USART2_TXDMA_BUF_SIZE];
|
||||||
|
int DataCntA; // data count in BufA
|
||||||
|
int DataCntB; // data count in BufB
|
||||||
|
int BufSelTx; // -1:none, 0:A, 1:B
|
||||||
|
int BufSelWr; // 0:A, 1:B
|
||||||
|
uint8_t FlushA;
|
||||||
|
uint8_t FlushB;
|
||||||
|
} Usart2TxBuf_t;
|
||||||
|
|
||||||
|
typedef void (*FuncProcData)(const uint8_t* data, uint16_t len);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Private macros ------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define ARRAY_COUNT(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
|
|
||||||
|
/* Private variables ---------------------------------------------------------*/
|
||||||
|
uint8_t Usart2RxDmaBuf[USART2_RXDMA_BUF_SIZE] = {0};
|
||||||
|
Usart2TxBuf_t Usart2TxDmaBuf = { {0},{0}, 0, 0, -1, 0 };
|
||||||
|
|
||||||
|
static FuncProcData ProcRxData = NULL; // function to process received data, set by Usart2_DMA_Init
|
||||||
|
|
||||||
|
|
||||||
|
/* Public variables ----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions -----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief USART2 init
|
||||||
|
*//****************************************************************************/
|
||||||
|
void Usart2_DMA_Init(void (*procRxData)(const uint8_t* data, uint16_t len)) {
|
||||||
|
ProcRxData = procRxData;
|
||||||
|
// USART and DMA initialization code should be generated by Cube MX
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief USART2 Rx/Tx DMA task, to be called periodically in main loop
|
||||||
|
*//****************************************************************************/
|
||||||
|
void Usart2_DMA_Task() {
|
||||||
|
// Handle received data from USART2 DMA
|
||||||
|
static uint32_t LastNDTR = USART2_RXDMA_BUF_SIZE;
|
||||||
|
static uint32_t WritePos = 0U;
|
||||||
|
uint32_t curNDTR = LL_DMA_GetBlkDataLength(USART2_GPDMA, USART2_DMA_RX_CHANNEL);
|
||||||
|
uint32_t newBytes;
|
||||||
|
if (curNDTR <= LastNDTR) { // no Wrap-Around
|
||||||
|
newBytes = LastNDTR - curNDTR;
|
||||||
|
}else { // NDTR is bigger than before: Wrap-Around occurred
|
||||||
|
newBytes = LastNDTR + (USART2_RXDMA_BUF_SIZE - curNDTR);
|
||||||
|
}
|
||||||
|
if (newBytes > 0U) {
|
||||||
|
uint32_t startPos = WritePos; // start of new data
|
||||||
|
uint32_t endPos = (WritePos + newBytes) % USART2_RXDMA_BUF_SIZE; // end of new data
|
||||||
|
if (startPos < endPos) { // no Wrap-Around
|
||||||
|
ProcRxData(&Usart2RxDmaBuf[startPos], newBytes);
|
||||||
|
} else { // first: to buffer end, second: from buffer begin
|
||||||
|
uint32_t part1 = USART2_RXDMA_BUF_SIZE - startPos;
|
||||||
|
ProcRxData(&Usart2RxDmaBuf[startPos], part1);
|
||||||
|
|
||||||
|
uint32_t part2 = newBytes - part1;
|
||||||
|
ProcRxData(&Usart2RxDmaBuf[0], part2);
|
||||||
|
}
|
||||||
|
// Store new Write Position and NDTR
|
||||||
|
WritePos = endPos; // next start position for write
|
||||||
|
LastNDTR = curNDTR; // NTDR value for next cycle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle USART2 Tx DMA transfer complete
|
||||||
|
if (LL_DMA_IsActiveFlag_TC(USART2_GPDMA, USART2_DMA_TX_CHANNEL)) {
|
||||||
|
LL_DMA_ClearFlag_TC(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
Usart2TxBuf_t* d = &Usart2TxDmaBuf;
|
||||||
|
switch (d->BufSelTx) {
|
||||||
|
case 0: { // transfer from BufA completed
|
||||||
|
d->BufSelTx = -1; // no transfer ongoing
|
||||||
|
d->DataCntA = 0; // reset BufA data count
|
||||||
|
if (d->FlushB) { // flush requested for BufB
|
||||||
|
// start transfer from BufB
|
||||||
|
LL_DMA_ClearFlag_TC(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART2_GPDMA, USART2_DMA_TX_CHANNEL, (uint32_t)d->BufB);
|
||||||
|
LL_DMA_SetBlkDataLength(USART2_GPDMA, USART2_DMA_TX_CHANNEL, d->DataCntB);
|
||||||
|
LL_DMA_EnableChannel(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
d->BufSelTx = 1; // mark transfer from BufB ongoing
|
||||||
|
d->BufSelWr = 0; // switch write to BufA
|
||||||
|
d->FlushB = 0; // clear flush request
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case 1: { // transfer from BufB completed
|
||||||
|
d->BufSelTx = -1; // no transfer ongoing
|
||||||
|
d->DataCntB = 0; // reset BufB data count
|
||||||
|
if (d->FlushA) { // flush requested for BufA
|
||||||
|
// start transfer from BufA
|
||||||
|
LL_DMA_ClearFlag_TC(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART2_GPDMA, USART2_DMA_TX_CHANNEL, (uint32_t)d->BufA);
|
||||||
|
LL_DMA_SetBlkDataLength(USART2_GPDMA, USART2_DMA_TX_CHANNEL, d->DataCntA);
|
||||||
|
LL_DMA_EnableChannel(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
d->BufSelTx = 0; // mark transfer from BufA ongoing
|
||||||
|
d->BufSelWr = 1; // switch write to BufB
|
||||||
|
d->FlushA = 0; // clear flush request
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief Write data to USART2 Tx buffer, and optionally start DMA transfer if flush is requested
|
||||||
|
* @param src: data to write
|
||||||
|
* @param n: count of data
|
||||||
|
* @param flush: if non-zero, request to start DMA transfer after writing data
|
||||||
|
*//****************************************************************************/
|
||||||
|
uint8_t Usart2_TxBufWrite(const void* src, size_t n, uint8_t flush) {
|
||||||
|
Usart2TxBuf_t* d = &Usart2TxDmaBuf;
|
||||||
|
switch (d->BufSelWr) {
|
||||||
|
case 0: { // BufA selected for write
|
||||||
|
int newpos = d->DataCntA + n;
|
||||||
|
if (newpos <= 2 * USART2_TXDMA_BUF_SIZE) { // enough space in the entire buffer
|
||||||
|
if (d->BufSelTx == 1 && newpos > USART2_TXDMA_BUF_SIZE) {
|
||||||
|
// transfer from BufB ongoing and BufA overflow
|
||||||
|
return 4; // overflow: skip data
|
||||||
|
}
|
||||||
|
memcpy(&d->BufA[d->DataCntA], src, n);
|
||||||
|
if (newpos > USART2_TXDMA_BUF_SIZE) { // BufA full
|
||||||
|
d->DataCntA = USART2_TXDMA_BUF_SIZE; // BufA full
|
||||||
|
// start transfer from BufA
|
||||||
|
LL_DMA_ClearFlag_TC(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART2_GPDMA, USART2_DMA_TX_CHANNEL, (uint32_t)d->BufA);
|
||||||
|
LL_DMA_SetBlkDataLength(USART2_GPDMA, USART2_DMA_TX_CHANNEL, d->DataCntA);
|
||||||
|
LL_DMA_EnableChannel(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
d->BufSelTx = 0; // mark transfer from BufA ongoing
|
||||||
|
d->BufSelWr = 1; // switch write to BufB
|
||||||
|
d->DataCntB = newpos - USART2_TXDMA_BUF_SIZE; // adjust BufB write position
|
||||||
|
if (flush) {
|
||||||
|
// BufA flush already started
|
||||||
|
d->FlushB = 1; // mark BufB flush requested
|
||||||
|
}
|
||||||
|
}else { // BufA not full yet
|
||||||
|
d->DataCntA = newpos;
|
||||||
|
if (flush) {
|
||||||
|
if (d->BufSelTx == -1) { // flush requested and no transfer ongoing
|
||||||
|
// start transfer from BufA
|
||||||
|
LL_DMA_ClearFlag_TC(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART2_GPDMA, USART2_DMA_TX_CHANNEL, (uint32_t)d->BufA);
|
||||||
|
LL_DMA_SetBlkDataLength(USART2_GPDMA, USART2_DMA_TX_CHANNEL, d->DataCntA);
|
||||||
|
LL_DMA_EnableChannel(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
d->BufSelTx = 0; // mark transfer from BufA ongoing
|
||||||
|
d->BufSelWr = 1; // switch write to BufB
|
||||||
|
}else {
|
||||||
|
d->FlushA = 1; // mark BufA flush requested
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else { // not enough space in the entire buffer
|
||||||
|
return 1; // overflow: skip data
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case 1: { // BufB selected for write
|
||||||
|
int newpos = d->DataCntB + n;
|
||||||
|
if (newpos <= USART2_TXDMA_BUF_SIZE) { // enough space in BufB
|
||||||
|
memcpy(&d->BufB[d->DataCntB], src, n);
|
||||||
|
d->DataCntB = newpos;
|
||||||
|
if (flush) {
|
||||||
|
if (d->BufSelTx == -1) { // flush requested and no transfer ongoing
|
||||||
|
// start transfer from BufB
|
||||||
|
LL_DMA_ClearFlag_TC(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART2_GPDMA, USART2_DMA_TX_CHANNEL, (uint32_t)d->BufB);
|
||||||
|
LL_DMA_SetBlkDataLength(USART2_GPDMA, USART2_DMA_TX_CHANNEL, d->DataCntB);
|
||||||
|
LL_DMA_EnableChannel(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
d->BufSelTx = 1; // mark transfer from BufB ongoing
|
||||||
|
d->BufSelWr = 0; // switch write to BufA
|
||||||
|
}else {
|
||||||
|
d->FlushB = 1; // mark BufB flush requested
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else { // not enough space in BufB
|
||||||
|
// try to flush BufB if possible
|
||||||
|
if (d->BufSelTx == -1) { // no transfer ongoing
|
||||||
|
// start transfer from BufB
|
||||||
|
LL_DMA_ClearFlag_TC(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART2_GPDMA, USART2_DMA_TX_CHANNEL, (uint32_t)d->BufB);
|
||||||
|
LL_DMA_SetBlkDataLength(USART2_GPDMA, USART2_DMA_TX_CHANNEL, d->DataCntB);
|
||||||
|
LL_DMA_EnableChannel(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
d->BufSelTx = 1; // mark transfer from BufB ongoing
|
||||||
|
d->BufSelWr = 0; // switch write to BufA
|
||||||
|
}
|
||||||
|
if (d->BufSelTx != 0) { // BufA ready to write (not being transmitted)
|
||||||
|
d->BufSelWr = 0; // switch write to BufA
|
||||||
|
if (n <= USART2_TXDMA_BUF_SIZE) { // enough space in BufA
|
||||||
|
memcpy(d->BufA, src, n);
|
||||||
|
d->DataCntA = n;
|
||||||
|
if (flush) { // flush requested
|
||||||
|
if (d->BufSelTx == -1) { // no transfer ongoing
|
||||||
|
// start transfer from BufA
|
||||||
|
LL_DMA_ClearFlag_TC(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART2_GPDMA, USART2_DMA_TX_CHANNEL, (uint32_t)d->BufA);
|
||||||
|
LL_DMA_SetBlkDataLength(USART2_GPDMA, USART2_DMA_TX_CHANNEL, d->DataCntA);
|
||||||
|
LL_DMA_EnableChannel(USART2_GPDMA, USART2_DMA_TX_CHANNEL);
|
||||||
|
d->BufSelTx = 0; // mark transfer from BufA ongoing
|
||||||
|
d->BufSelWr = 1; // switch write to BufB
|
||||||
|
}else { // transfer ongoing
|
||||||
|
d->FlushA = 1; // mark BufA flush requested
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
return 2; // overflow: skip data
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
return 3; // overflow: skip data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
return 0; // no error
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue