USART3 DMA RX/TX works
- Rx/Tx handler in usart3_dma.* - CubeMX: USART and DMA init - DMA CH0: Tx - DMA CH1: 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
2e7c0f82a6
commit
336c397135
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef __USART3_IT_H__
|
||||||
|
#define __USART3_IT_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "usart3_dma_cfg.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern uint8_t Usart3RxDmaBuf[USART3_RXDMA_BUF_SIZE];
|
||||||
|
|
||||||
|
extern void Usart3_DMA_Init(void (*)(const uint8_t* data, uint16_t len));
|
||||||
|
extern void Usart3_DMA_Task();
|
||||||
|
extern void Usart3_PutByte(uint8_t d);
|
||||||
|
extern void Usart3_PutData(const void* src, uint16_t n);
|
||||||
|
extern int16_t Usart3_GetByte(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __USART3_IT_CFG_H__
|
||||||
|
#define __USART3_IT_CFG_H__
|
||||||
|
|
||||||
|
#include "stm32h5xx_ll_dma.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define USART3_RXDMA_BUF_SIZE 2048
|
||||||
|
#define USART3_TXDMA_BUF_SIZE 2048
|
||||||
|
|
||||||
|
#define USART3_GPDMA GPDMA1
|
||||||
|
#define USART3_DMA_TX_CHANNEL LL_DMA_CHANNEL_0
|
||||||
|
#define USART3_DMA_RX_CHANNEL LL_DMA_CHANNEL_1
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __USART3_CFG_H__
|
||||||
@ -0,0 +1,238 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file usart3_dma.c
|
||||||
|
* @brief UART with DMA
|
||||||
|
*//****************************************************************************/
|
||||||
|
|
||||||
|
//------------------------------C library---------------------------------------
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
//----------------------------user includes-------------------------------------
|
||||||
|
#include "usart3_dma.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Private typedefs ----------------------------------------------------------*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t BufA[USART3_TXDMA_BUF_SIZE];
|
||||||
|
uint8_t BufB[USART3_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;
|
||||||
|
} Usart3TxBuf_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 Usart3RxDmaBuf[USART3_RXDMA_BUF_SIZE] = {0};
|
||||||
|
Usart3TxBuf_t Usart3TxDmaBuf = { {0},{0}, 0, 0, -1, 0 };
|
||||||
|
|
||||||
|
static FuncProcData ProcRxData = NULL; // function to process received data, set by Usart3_DMA_Init
|
||||||
|
|
||||||
|
|
||||||
|
/* Public variables ----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions -----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief USART3 init
|
||||||
|
*//****************************************************************************/
|
||||||
|
void Usart3_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 USART3 Rx/Tx DMA task, to be called periodically in main loop
|
||||||
|
*//****************************************************************************/
|
||||||
|
void Usart3_DMA_Task() {
|
||||||
|
// Handle received data from USART3 DMA
|
||||||
|
static uint32_t LastNDTR = USART3_RXDMA_BUF_SIZE;
|
||||||
|
static uint32_t WritePos = 0U;
|
||||||
|
uint32_t curNDTR = LL_DMA_GetBlkDataLength(USART3_GPDMA, USART3_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 + (USART3_RXDMA_BUF_SIZE - curNDTR);
|
||||||
|
}
|
||||||
|
if (newBytes > 0U) {
|
||||||
|
uint32_t startPos = WritePos; // start of new data
|
||||||
|
uint32_t endPos = (WritePos + newBytes) % USART3_RXDMA_BUF_SIZE; // end of new data
|
||||||
|
if (startPos < endPos) { // no Wrap-Around
|
||||||
|
ProcRxData(&Usart3RxDmaBuf[startPos], newBytes);
|
||||||
|
} else { // first: to buffer end, second: from buffer begin
|
||||||
|
uint32_t part1 = USART3_RXDMA_BUF_SIZE - startPos;
|
||||||
|
ProcRxData(&Usart3RxDmaBuf[startPos], part1);
|
||||||
|
|
||||||
|
uint32_t part2 = newBytes - part1;
|
||||||
|
ProcRxData(&Usart3RxDmaBuf[0], part2);
|
||||||
|
}
|
||||||
|
// Store new Write Position and NDTR
|
||||||
|
WritePos = endPos; // next start position for write
|
||||||
|
LastNDTR = curNDTR; // NTDR value for next cycle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle USART3 Tx DMA transfer complete
|
||||||
|
if (LL_DMA_IsActiveFlag_TC(USART3_GPDMA, USART3_DMA_TX_CHANNEL)) {
|
||||||
|
LL_DMA_ClearFlag_TC(USART3_GPDMA, USART3_DMA_TX_CHANNEL);
|
||||||
|
Usart3TxBuf_t* d = &Usart3TxDmaBuf;
|
||||||
|
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(USART3_GPDMA, USART3_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART3_GPDMA, USART3_DMA_TX_CHANNEL, (uint32_t)d->BufB);
|
||||||
|
LL_DMA_SetBlkDataLength(USART3_GPDMA, USART3_DMA_TX_CHANNEL, d->DataCntB);
|
||||||
|
LL_DMA_EnableChannel(USART3_GPDMA, USART3_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(USART3_GPDMA, USART3_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART3_GPDMA, USART3_DMA_TX_CHANNEL, (uint32_t)d->BufA);
|
||||||
|
LL_DMA_SetBlkDataLength(USART3_GPDMA, USART3_DMA_TX_CHANNEL, d->DataCntA);
|
||||||
|
LL_DMA_EnableChannel(USART3_GPDMA, USART3_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 USART3 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 Usart3_TxBufWrite(const void* src, size_t n, uint8_t flush) {
|
||||||
|
Usart3TxBuf_t* d = &Usart3TxDmaBuf;
|
||||||
|
switch (d->BufSelWr) {
|
||||||
|
case 0: { // BufA selected for write
|
||||||
|
int newpos = d->DataCntA + n;
|
||||||
|
if (newpos <= 2 * USART3_TXDMA_BUF_SIZE) { // enough space in the entire buffer
|
||||||
|
if (d->BufSelTx == 1 && newpos > USART3_TXDMA_BUF_SIZE) {
|
||||||
|
// transfer from BufB ongoing and BufA overflow
|
||||||
|
return 4; // overflow: skip data
|
||||||
|
}
|
||||||
|
memcpy(&d->BufA[d->DataCntA], src, n);
|
||||||
|
if (newpos > USART3_TXDMA_BUF_SIZE) { // BufA full
|
||||||
|
d->DataCntA = USART3_TXDMA_BUF_SIZE; // BufA full
|
||||||
|
// start transfer from BufA
|
||||||
|
LL_DMA_ClearFlag_TC(USART3_GPDMA, USART3_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART3_GPDMA, USART3_DMA_TX_CHANNEL, (uint32_t)d->BufA);
|
||||||
|
LL_DMA_SetBlkDataLength(USART3_GPDMA, USART3_DMA_TX_CHANNEL, d->DataCntA);
|
||||||
|
LL_DMA_EnableChannel(USART3_GPDMA, USART3_DMA_TX_CHANNEL);
|
||||||
|
d->BufSelTx = 0; // mark transfer from BufA ongoing
|
||||||
|
d->BufSelWr = 1; // switch write to BufB
|
||||||
|
d->DataCntB = newpos - USART3_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(USART3_GPDMA, USART3_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART3_GPDMA, USART3_DMA_TX_CHANNEL, (uint32_t)d->BufA);
|
||||||
|
LL_DMA_SetBlkDataLength(USART3_GPDMA, USART3_DMA_TX_CHANNEL, d->DataCntA);
|
||||||
|
LL_DMA_EnableChannel(USART3_GPDMA, USART3_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 <= USART3_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(USART3_GPDMA, USART3_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART3_GPDMA, USART3_DMA_TX_CHANNEL, (uint32_t)d->BufB);
|
||||||
|
LL_DMA_SetBlkDataLength(USART3_GPDMA, USART3_DMA_TX_CHANNEL, d->DataCntB);
|
||||||
|
LL_DMA_EnableChannel(USART3_GPDMA, USART3_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(USART3_GPDMA, USART3_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART3_GPDMA, USART3_DMA_TX_CHANNEL, (uint32_t)d->BufB);
|
||||||
|
LL_DMA_SetBlkDataLength(USART3_GPDMA, USART3_DMA_TX_CHANNEL, d->DataCntB);
|
||||||
|
LL_DMA_EnableChannel(USART3_GPDMA, USART3_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 <= USART3_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(USART3_GPDMA, USART3_DMA_TX_CHANNEL);
|
||||||
|
LL_DMA_SetSrcAddress(USART3_GPDMA, USART3_DMA_TX_CHANNEL, (uint32_t)d->BufA);
|
||||||
|
LL_DMA_SetBlkDataLength(USART3_GPDMA, USART3_DMA_TX_CHANNEL, d->DataCntA);
|
||||||
|
LL_DMA_EnableChannel(USART3_GPDMA, USART3_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