一、项目概述
本项目基于 STM32 N647(Cortex‑M55),实现UART+GPDMA 环形缓冲区异步接收标准 MIDI 31250 波特率数据流,搭配 1ms 定时轮询完成协议解析、半包粘包容错、溢出丢包保护、消息队列缓冲,完整实现工业级 MIDI 实时接收与消息分发。
二、核心技术方案
底层传输
采用 GPDMA 循环链表模式,无 CPU 干预自动串口接收,解放内核算力;接收缓冲区 32 字节严格 Cache 行对齐,配合SCB_InvalidateDCache_by_Addr维护 D-Cache 一致性,避免脏数据解析异常。
环形缓冲区设计
采用rxWriteTotal/rxReadTotal全局轮回计数,支持多圈 DMA 溢出;限制最大可读数据为缓冲大小 - 1,预留 1 字节安全间隙,杜绝 DMA 后台写入与前台读取数据踩踏。
溢出与丢包机制
处理速率不足时自动舍弃老旧数据,仅保留最新一整段有效数据;精准统计溢出丢弃字节数,可实时上报收发状态与故障统计。
MIDI 协议解析逻辑
逐字节搜索MIDI 状态字(0x80~0xFF) 自动同步帧边界;
按状态字区分1/2/3 字节标准消息格式;
数据长度不足时自动终止解析,残留半包留待下 1ms 周期继续处理;
非法格式、违规数据字节逐字节丢弃,自动恢复同步,避免永久乱码。
消息队列调度
内置 128 级消息环形队列,解析完成消息入队,业务层异步取走解耦处理;同时统计解析成功、已处理、无效消息三类计数,便于调试与性能评估。
三、关键难点与解决方案
Cache 一致性问题:缓冲区 32 字节对齐 + 读取前主动 Cache 无效化,彻底解决 DMA 与 CPU 缓存数据不同步。
DMA 计数器读取撕裂:采用短临界区原子读取,1ms 周期纳秒级关中断,不影响系统实时性。
多圈缓冲区溢出:用全局总读写计数替代单指针,可识别并丢弃多圈积压数据,快速复位读指针到最新有效位置。
MIDI 半包 / 粘包容错:不按固定长度切块,采用状态机逐字节遍历,数据不足即退出,天然兼容不定长 MIDI 报文。
高内聚封装:面向对象 C++ 封装,自动适配多串口、引脚与时钟配置,初始化后一键启动,接口简洁易移植。
四、功能与性能指标
波特率:标准 MIDI 31250bps;
缓冲区:512 字节 32 字节对齐环形接收缓冲;
消息队列:128 级环形消息缓存;
调度周期:1ms 定时解析,延迟低、实时性强;
容错能力:自动丢包统计、帧同步恢复、非法数据过滤、半包续解析;
架构优势:DMA 全自动传输、无阻塞接收、内核开销极小、可直接量产复用。
五、项目特色亮点
全程遵循嵌入式工程规范:内存对齐、Cache 维护、原子操作、临界区保护齐全;
自研多圈环形缓冲区算法,解决传统单指针无法处理多轮溢出的缺陷;
MIDI 解析逻辑贴合协议原生规范,容错健壮,无卡死、无永久乱码;
高内聚低耦合封装,一行初始化即可适配不同 USART 外设,可复用至同类音频、MIDI 设备项目。
下面是类封装代码:
/*****************************************************************************************
* @class MIDI
* @brief 基于 UART + GPDMA 环形缓冲区 的标准 MIDI 1.0 解析类
*
* @details 工作架构(产品级设计):
* 1. UART + DMA 环形缓冲区后台持续接收 MIDI 原始数据
* 2. DMA 中断仅更新缓冲区轮回计数,不执行解析
* 3. 建议使用 1ms 定时器定时调用 refreshMessage() 解析已接收数据
* 4. 解析完成的 MIDI 消息存入队列,支持异步读取
* 5. 自动处理数据溢出、防阻塞、防解析错乱
* 6. 支持标准通道消息 + 系统实时/公共消息,自动跳过 SysEx
*
* @note MIDI 硬件标准:31250 波特率,8N1,无校验
* @note 消息格式(uint32_t):
* - [7:0] MIDI 状态字节(命令)
* - [15:8] 数据字节 1
* - [23:16] 数据字节 2
*
* @usage 使用流程:
* 1. 创建 MIDI 实例
* 2. 调用 init() 初始化 UART / GPIO / DMA / 中断
* 3. 调用 Start() 启动 DMA 接收
* 4. 在 DMA 中断中调用 RxCallback()
* 5. 在 1ms 定时器中调用 refreshMessage() 解析数据
* 6. 调用 getMessage() 读取并处理已解析的 MIDI 消息
*
* @author 悟渔
* @date 2026-05-01
****************************************************************************************/
class MIDI{
public:
static constexpr const uint16_t RX_BUF_SIZE = 512;//串行接收缓冲区大小(必须32字节对齐)。
static constexpr const uint16_t MSG_QUEUE_SIZE = 128;//MIDI消息缓冲区大小。
private:
uint8_t*rxBuffer=nullptr;
uint16_t rxBufferSize=0;
uint32_t midiMsgQueue[MSG_QUEUE_SIZE]={0};//midi消息队列。每一个数据四个字节,从低字节到高字节分别表示控制字和控制数据。每条MIDI消息最多可以带3个字节的数据。
uint32_t midiMsgWritePtr=0;
uint32_t midiMsgReadPtr=0;
uint32_t parsedMsgCount = 0; // 解析成功的MIDI消息计数
uint32_t processedMsgCount = 0; // 已处理MIDI消息计数。
uint32_t invalidMsgCount = 0; //无效/不识别消息计数
uint8_t rxBufferData[RX_BUF_SIZE] __attribute__((aligned(32)));//接收缓冲区(32字节对齐)。
uint32_t rxWriteTotal = 0,rxReadTotal = 0;//读/写轮回计数。
uint32_t rxWritePtr=0,rxReadPtr=0;//读写指针。
uint32_t rxOverflowCount=0;//溢出(丢包)统计。表示因为处理速度太慢而丢弃的数据量。
UART_HandleTypeDef* huartHandle;//串口句柄。
DMA_HandleTypeDef* gpdmaHandle;//GPDMA句柄。
DMA_QListTypeDef* List;
DMA_NodeTypeDef * MidiNode;
protected:
public:
MIDI(){
huartHandle = nullptr;
gpdmaHandle = nullptr;
List = nullptr;
MidiNode = nullptr;
rxBuffer = nullptr;
rxBufferSize = 0;
rxWriteTotal = 0;
rxReadTotal = 0;
rxWritePtr = 0;
rxReadPtr = 0;
rxOverflowCount= 0;
midiMsgWritePtr= 0;
midiMsgReadPtr = 0;
parsedMsgCount = 0;
processedMsgCount = 0;
invalidMsgCount = 0;
}
HAL_StatusTypeDef Start(uint8_t* InReceiveBuffer=nullptr,uint16_t InBufferSize=0){
if(huartHandle == nullptr || gpdmaHandle == nullptr){return HAL_ERROR;}
rxBuffer=(InReceiveBuffer != nullptr)?InReceiveBuffer:rxBufferData;
rxBufferSize=((InBufferSize > 0) && (InBufferSize <= RX_BUF_SIZE) && ((InBufferSize % 32) == 0))?InBufferSize:RX_BUF_SIZE;
rxReadPtr = 0;
rxWritePtr = 0;
rxWriteTotal = 0;
rxReadTotal = 0;
rxOverflowCount = 0;
midiMsgWritePtr=0;
midiMsgReadPtr=0;
parsedMsgCount = 0;
processedMsgCount = 0;
invalidMsgCount = 0;
if(HAL_UART_DMAStop(huartHandle) != HAL_OK)return HAL_ERROR;
return HAL_UART_Receive_DMA(huartHandle, rxBuffer, rxBufferSize);
}
HAL_StatusTypeDef RxCallback(void){
//缓冲区满回调(循环模式会自动从头接收)。
rxWriteTotal += rxBufferSize;
return HAL_OK;
}
HAL_StatusTypeDef getMessage(uint32_t * InMidiMessage){
if(midiMsgReadPtr == midiMsgWritePtr || InMidiMessage == nullptr){return HAL_ERROR;}
*InMidiMessage=midiMsgQueue[midiMsgReadPtr];
processedMsgCount++;//统计取走的MIDI消息数量(已处理消息数量)。
midiMsgReadPtr=(midiMsgReadPtr+1)%MSG_QUEUE_SIZE;
return HAL_OK;
}
HAL_StatusTypeDef getMidiStatistics(uint64_t *totalReceivedBytes,uint32_t *lostBytes,uint32_t *currentAvailableBytes,uint32_t *parsedMessageCount,uint32_t *processedMessageCount)
{
// 参数返回:总接收字节数、丢包字节数、接收缓冲区未读字节数、正确解析成功的消息总数、已被处理的消息总数。
if (totalReceivedBytes == nullptr || lostBytes == nullptr || currentAvailableBytes == nullptr || parsedMessageCount == nullptr || processedMessageCount == nullptr){return HAL_ERROR;}
*totalReceivedBytes = (uint64_t)rxWriteTotal + rxWritePtr;
*lostBytes = rxOverflowCount;
int64_t available = (uint64_t)rxWriteTotal + rxWritePtr - (uint64_t)rxReadTotal;
*currentAvailableBytes = available > 0 ? (uint32_t)available : 0;
*parsedMessageCount = parsedMsgCount;
*processedMessageCount = processedMsgCount;
return HAL_OK;
}
HAL_StatusTypeDef refreshMessage(){
//读取并解析MIDI消息,被正确识别的消息存入MIDI消息队列。
if(huartHandle == nullptr || gpdmaHandle == nullptr || rxBuffer == nullptr){return HAL_ERROR;}
static uint8_t TemData[RX_BUF_SIZE];//数据暂存。
uint32_t available;//可读数据量(接收数据的数量)。
uint32_t TemrxReadPtr;
uint8_t TemByte;
uint8_t TemByte_H=0,TemByte_L=0;
__disable_irq(); // 关中断(原子操作,防止读取数据时被打断。)
uint32_t temRxWriteCount=__HAL_DMA_GET_COUNTER(gpdmaHandle);
__enable_irq(); // 开中断
rxWritePtr =rxBufferSize - temRxWriteCount;//通过剩余接收数据量获得写指针位置。
if(rxWritePtr >= rxBufferSize){rxWritePtr = 0;}
SCB_InvalidateDCache_by_Addr((uint32_t*)rxBuffer, rxBufferSize);//rxBufferSize是通过程序天然保证32字节对齐的,所以这里不用检查。
uint32_t totalWritten = rxWriteTotal + rxWritePtr; // 总写入 = 完整缓冲区 + 当前指针
uint32_t totalRead = rxReadTotal; // 总读取
if(totalWritten<=totalRead){return HAL_ERROR;}
available = totalWritten - totalRead; // 真正可用数据
if(available >= rxBufferSize)
{
rxOverflowCount += available - (rxBufferSize-1);
available = rxBufferSize-1;
rxReadTotal = totalWritten - available;
rxReadPtr = (uint32_t)(rxReadTotal % rxBufferSize);
}
TemrxReadPtr=rxReadPtr;
//拷贝全部缓冲数据,避免中途数据被覆盖。
for(uint16_t Index=0;Index<available;Index++){
TemData[Index]=rxBuffer[TemrxReadPtr];
TemrxReadPtr++;
if(TemrxReadPtr>=rxBufferSize){TemrxReadPtr-=rxBufferSize;}
}
TemrxReadPtr=0;//决定以后搜索MIDI命令字的起点(默认一个命令字都没有,将丢弃所有数据)。
while(TemrxReadPtr<available){
TemByte=TemData[TemrxReadPtr];
TemByte_H = TemByte & 0xF0;
TemByte_L = TemByte & 0x0F;
if((TemByte_H >= 0x80 && TemByte_H <= 0xE0 && TemByte_H !=0xC0 && TemByte_H !=0xD0) || (TemByte_H == 0xF0 && TemByte_L == 0x02)){// 三字节消息。
if( TemrxReadPtr+2 >= available){break;}//数据量不够。
if(TemData[TemrxReadPtr+1] > 0x7F){invalidMsgCount+=1;TemrxReadPtr+=1;continue;}//数据非法。
if(TemData[TemrxReadPtr+2] > 0x7F){invalidMsgCount+=1;TemrxReadPtr+=2;continue;}//数据非法。
midiMsgQueue[midiMsgWritePtr]=((uint32_t)TemData[TemrxReadPtr+2]<<16) | ((uint32_t)TemData[TemrxReadPtr+1] << 8) | (uint32_t)TemData[TemrxReadPtr];
parsedMsgCount++;
midiMsgWritePtr++;if(midiMsgWritePtr >= MSG_QUEUE_SIZE){midiMsgWritePtr -= MSG_QUEUE_SIZE;}
if(midiMsgWritePtr == midiMsgReadPtr){invalidMsgCount+=1;midiMsgReadPtr=(midiMsgWritePtr+1);if(midiMsgReadPtr >= MSG_QUEUE_SIZE){midiMsgReadPtr-=MSG_QUEUE_SIZE;}}
TemrxReadPtr+=3;
}else if(TemByte_H == 0xC0 || TemByte_H == 0xD0 || (TemByte_H == 0xF0 && (TemByte_L == 0x01 || TemByte_L == 0x03))){//两字节消息。
if( TemrxReadPtr+1 >= available){break;}//数据量不够。
if(TemData[TemrxReadPtr+1] > 0x7F){invalidMsgCount+=1;TemrxReadPtr+=1;continue;}//数据非法。
midiMsgQueue[midiMsgWritePtr]=((uint32_t)TemData[TemrxReadPtr+1] << 8) | (uint32_t)TemData[TemrxReadPtr];
parsedMsgCount++;
midiMsgWritePtr++;if(midiMsgWritePtr >= MSG_QUEUE_SIZE){midiMsgWritePtr -= MSG_QUEUE_SIZE;}
if(midiMsgWritePtr == midiMsgReadPtr){invalidMsgCount+=1;midiMsgReadPtr=(midiMsgWritePtr+1);if(midiMsgReadPtr >= MSG_QUEUE_SIZE){midiMsgReadPtr-=MSG_QUEUE_SIZE;}}
TemrxReadPtr+=2;
}else if(TemByte_H == 0xF0 && TemByte_L != 0x00){//单字节消息。
midiMsgQueue[midiMsgWritePtr]=(uint32_t)TemData[TemrxReadPtr];
parsedMsgCount++;
midiMsgWritePtr++;if(midiMsgWritePtr >= MSG_QUEUE_SIZE){midiMsgWritePtr -= MSG_QUEUE_SIZE;}
if(midiMsgWritePtr == midiMsgReadPtr){invalidMsgCount+=1;midiMsgReadPtr=(midiMsgWritePtr+1);if(midiMsgReadPtr >= MSG_QUEUE_SIZE){midiMsgReadPtr-=MSG_QUEUE_SIZE;}}
TemrxReadPtr+=1;
}else{//不支持的系统消息或不被识别的、错误的消息直接抛弃。
invalidMsgCount++;
TemrxReadPtr+=1;
}
}
rxReadPtr=(rxReadPtr+TemrxReadPtr);
if(rxReadPtr >= rxBufferSize){rxReadPtr -= rxBufferSize;}
rxReadTotal += TemrxReadPtr;
if(TemrxReadPtr>0){return HAL_OK;}else{return HAL_ERROR;}
}
HAL_StatusTypeDef init(UART_HandleTypeDef* In_HuartHandle,DMA_HandleTypeDef* In_DmaHandle,DMA_QListTypeDef * InList,DMA_NodeTypeDef * InNode,uint32_t IRQn) {
if(In_HuartHandle == nullptr || In_DmaHandle == nullptr || InList == nullptr || InNode == nullptr){return HAL_ERROR;}
List=InList;
MidiNode=InNode;
IRQn=(IRQn>15)?15:IRQn;
huartHandle=In_HuartHandle;gpdmaHandle=In_DmaHandle;
DMA_NodeConfTypeDef NodeConfig;
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
GPIO_TypeDef *GPIOx_T;uint16_t GPIO_pin_T;
GPIO_TypeDef *GPIOx_R;uint16_t GPIO_pin_R;
uint32_t GPIO_Alternate;
IRQn_Type IRQ_Driver;
uint32_t Request;
#ifdef USART1
if(huartHandle->Instance == USART1){
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART1;
PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_CLKP;
GPIOx_T=GPIOC;GPIO_pin_T=GPIO_PIN_4;
GPIOx_R=GPIOE;GPIO_pin_R=GPIO_PIN_6;
GPIO_Alternate=GPIO_AF7_USART1;
__HAL_RCC_USART1_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOE_CLK_ENABLE();
IRQ_Driver=USART1_IRQn;
Request=GPDMA1_REQUEST_USART1_RX;
}
#endif
#ifdef USART2
if(huartHandle->Instance == USART2){
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART2;
PeriphClkInitStruct.Usart2ClockSelection = RCC_USART2CLKSOURCE_CLKP;
GPIOx_T=GPIOD;GPIO_pin_T=GPIO_PIN_5;
GPIOx_R=GPIOF;GPIO_pin_R=GPIO_PIN_6;
GPIO_Alternate=GPIO_AF7_USART2;
__HAL_RCC_USART2_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOF_CLK_ENABLE();
IRQ_Driver=USART2_IRQn;
Request=GPDMA1_REQUEST_USART2_RX;
}
#endif
#ifdef USART3
if(huartHandle->Instance == USART3){
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART3;
PeriphClkInitStruct.Usart3ClockSelection = RCC_USART3CLKSOURCE_CLKP;
GPIOx_T=GPIOC;GPIO_pin_T=GPIO_PIN_10;
GPIOx_R=GPIOD;GPIO_pin_R=GPIO_PIN_9;
GPIO_Alternate=GPIO_AF7_USART3;
__HAL_RCC_USART3_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();
IRQ_Driver=USART3_IRQn;
Request=GPDMA1_REQUEST_USART3_RX;
}
#endif
#ifdef UART4
if(huartHandle->Instance == UART4){
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_UART4;
PeriphClkInitStruct.Uart4ClockSelection = RCC_UART4CLKSOURCE_CLKP;
GPIOx_T=GPIOC;GPIO_pin_T=GPIO_PIN_1;
GPIOx_R=GPIOC;GPIO_pin_R=GPIO_PIN_11;
GPIO_Alternate=GPIO_AF8_UART4;
__HAL_RCC_UART4_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();
IRQ_Driver=UART4_IRQn;
Request=GPDMA1_REQUEST_UART4_RX;
}
#endif
#ifdef UART5
if(huartHandle->Instance == UART5){
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_UART5;
PeriphClkInitStruct.Uart5ClockSelection = RCC_UART5CLKSOURCE_CLKP;
GPIOx_T=GPIOC;GPIO_pin_T=GPIO_PIN_12;
GPIOx_R=GPIOH;GPIO_pin_R=GPIO_PIN_2;
GPIO_Alternate=GPIO_AF11_UART5;
__HAL_RCC_UART5_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOH_CLK_ENABLE();
IRQ_Driver=UART5_IRQn;
Request=GPDMA1_REQUEST_UART5_RX;
}
#endif
#ifdef USART6
if(huartHandle->Instance == USART6){
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART6;
PeriphClkInitStruct.Usart6ClockSelection = RCC_USART6CLKSOURCE_CLKP;
GPIOx_T=GPIOC;GPIO_pin_T=GPIO_PIN_6;
GPIOx_R=GPIOC;GPIO_pin_R=GPIO_PIN_9;
GPIO_Alternate=GPIO_AF7_USART6;
__HAL_RCC_USART6_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();
IRQ_Driver=USART6_IRQn;
Request=GPDMA1_REQUEST_USART6_RX;
}
#endif
#ifdef UART7
if(huartHandle->Instance == UART7){
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_UART7;
PeriphClkInitStruct.Uart7ClockSelection = RCC_UART7CLKSOURCE_CLKP;
GPIOx_T=GPIOE;GPIO_pin_T=GPIO_PIN_7;
GPIOx_R=GPIOE;GPIO_pin_R=GPIO_PIN_8;
GPIO_Alternate=GPIO_AF8_UART7;
__HAL_RCC_UART7_CLK_ENABLE();__HAL_RCC_GPIOE_CLK_ENABLE();
IRQ_Driver=UART7_IRQn;
Request=GPDMA1_REQUEST_UART7_RX;
}
#endif
#ifdef UART8
if(huartHandle->Instance == UART8){
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_UART8;
PeriphClkInitStruct.Uart8ClockSelection = RCC_UART8CLKSOURCE_CLKP;
GPIOx_T=GPIOE;GPIO_pin_T=GPIO_PIN_0;
GPIOx_R=GPIOE;GPIO_pin_R=GPIO_PIN_1;
GPIO_Alternate=GPIO_AF8_UART8;
__HAL_RCC_UART8_CLK_ENABLE();__HAL_RCC_GPIOE_CLK_ENABLE();
IRQ_Driver=UART8_IRQn;
Request=GPDMA1_REQUEST_UART8_RX;
}
#endif
#ifdef UART9
if(huartHandle->Instance == UART9){
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_UART9;
PeriphClkInitStruct.Uart9ClockSelection = RCC_UART9CLKSOURCE_CLKP;
GPIOx_T=GPIOF;GPIO_pin_T=GPIO_PIN_0;
GPIOx_R=GPIOF;GPIO_pin_R=GPIO_PIN_1;
GPIO_Alternate=GPIO_AF7_UART9;
__HAL_RCC_UART9_CLK_ENABLE();__HAL_RCC_GPIOF_CLK_ENABLE();
IRQ_Driver=UART9_IRQn;
Request=GPDMA1_REQUEST_UART9_RX;
}
#endif
#ifdef USART10
if(huartHandle->Instance == USART10){
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART10;
PeriphClkInitStruct.Usart10ClockSelection = RCC_USART10CLKSOURCE_CLKP;
GPIOx_T=GPIOD;GPIO_pin_T=GPIO_PIN_14;
GPIOx_R=GPIOD;GPIO_pin_R=GPIO_PIN_15;
GPIO_Alternate=GPIO_AF6_USART10;
__HAL_RCC_USART10_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();
IRQ_Driver=USART10_IRQn;
Request=GPDMA1_REQUEST_USART10_RX;
}
#endif
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){return HAL_ERROR;}
GPIO_InitStruct.Pin = GPIO_pin_T;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_Alternate;
HAL_GPIO_Init(GPIOx_T, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_pin_R;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_Alternate;
HAL_GPIO_Init(GPIOx_R, &GPIO_InitStruct);
DMA_Channel_TypeDef * TemDmaHandleInstance=gpdmaHandle->Instance;
if (HAL_DMA_DeInit(gpdmaHandle) != HAL_OK){return HAL_ERROR;}
NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
NodeConfig.Init.Request = Request;
NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
NodeConfig.Init.SrcBurstLength = 1;
NodeConfig.Init.DestBurstLength = 1;
NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
NodeConfig.Init.Mode = DMA_NORMAL;
NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
NodeConfig.SrcSecure = DMA_CHANNEL_SRC_SEC;
NodeConfig.DestSecure = DMA_CHANNEL_DEST_SEC;
if (HAL_DMAEx_List_BuildNode(&NodeConfig, MidiNode) != HAL_OK){return HAL_ERROR;}
if (HAL_DMAEx_List_InsertNode(List, NULL, MidiNode) != HAL_OK){return HAL_ERROR;}
if (HAL_DMAEx_List_SetCircularMode(List) != HAL_OK){return HAL_ERROR;}
gpdmaHandle->Instance = TemDmaHandleInstance;
gpdmaHandle->InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
gpdmaHandle->InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
gpdmaHandle->InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
gpdmaHandle->InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
gpdmaHandle->InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
if (HAL_DMAEx_List_Init(gpdmaHandle) != HAL_OK){return HAL_ERROR;}
if (HAL_DMAEx_List_LinkQ(gpdmaHandle, List) != HAL_OK){return HAL_ERROR;}
huartHandle->hdmarx=gpdmaHandle;gpdmaHandle->Parent=huartHandle;
HAL_NVIC_SetPriority(IRQ_Driver, IRQn, 0);HAL_NVIC_EnableIRQ(IRQ_Driver);
USART_TypeDef *TemUsartInstance=huartHandle->Instance;
if (HAL_UART_DeInit(huartHandle) != HAL_OK){return HAL_ERROR;}
huartHandle->Instance=TemUsartInstance;
huartHandle->Init.BaudRate = 31250;
huartHandle->Init.WordLength = UART_WORDLENGTH_8B;
huartHandle->Init.StopBits = UART_STOPBITS_1;
huartHandle->Init.Parity = UART_PARITY_NONE;
huartHandle->Init.Mode = UART_MODE_TX_RX;
huartHandle->Init.HwFlowCtl = UART_HWCONTROL_NONE;
huartHandle->Init.OverSampling = UART_OVERSAMPLING_16;
huartHandle->Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huartHandle->Init.ClockPrescaler = UART_PRESCALER_DIV1;
huartHandle->AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(huartHandle) != HAL_OK){return HAL_ERROR;}
if (HAL_UARTEx_SetTxFifoThreshold(huartHandle, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK){return HAL_ERROR;}
if (HAL_UARTEx_SetRxFifoThreshold(huartHandle, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK){return HAL_ERROR;}
if (HAL_UARTEx_DisableFifoMode(huartHandle) != HAL_OK){return HAL_ERROR;}
return Start(rxBuffer,rxBufferSize);
}
};