mirror of
https://github.com/m5stack/M5Chain-Series-Internal-FW.git
synced 2026-05-20 11:49:54 -07:00
442 lines
15 KiB
C
442 lines
15 KiB
C
/* USER CODE BEGIN Header */
|
|
/**
|
|
******************************************************************************
|
|
* @file usart.c
|
|
* @brief This file provides code for the configuration
|
|
* of the USART instances.
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* Copyright (c) 2024 STMicroelectronics.
|
|
* All rights reserved.
|
|
*
|
|
* This software is licensed under terms that can be found in the LICENSE file
|
|
* in the root directory of this software component.
|
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
/* USER CODE END Header */
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "usart.h"
|
|
|
|
/* USER CODE BEGIN 0 */
|
|
|
|
__IO circular_buffer tx_in_buffer = {0};
|
|
__IO circular_buffer tx_out_buffer = {0};
|
|
|
|
/* USER CODE END 0 */
|
|
|
|
/* USART1 init function */
|
|
|
|
void MX_USART1_UART_Init(void) {
|
|
|
|
/* USER CODE BEGIN USART1_Init 0 */
|
|
|
|
/* USER CODE END USART1_Init 0 */
|
|
|
|
LL_USART_InitTypeDef USART_InitStruct = {0};
|
|
|
|
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
|
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
|
|
|
|
/** Initializes the peripherals clocks
|
|
*/
|
|
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
|
|
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
|
|
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
|
|
Error_Handler();
|
|
}
|
|
|
|
/* Peripheral clock enable */
|
|
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
|
|
|
|
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
|
|
/**USART1 GPIO Configuration
|
|
PB6 ------> USART1_TX
|
|
PB7 ------> USART1_RX
|
|
*/
|
|
GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
|
|
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
|
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
|
|
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
|
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
|
|
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
|
|
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
|
|
|
GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
|
|
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
|
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
|
|
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
|
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
|
|
GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
|
|
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
|
|
|
/* USART1 DMA Init */
|
|
|
|
/* USART1_RX Init */
|
|
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_USART1_RX);
|
|
|
|
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1,
|
|
LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
|
|
|
|
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW);
|
|
|
|
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_NORMAL);
|
|
|
|
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
|
|
|
|
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
|
|
|
|
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_BYTE);
|
|
|
|
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_BYTE);
|
|
|
|
/* USART1_TX Init */
|
|
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_USART1_TX);
|
|
|
|
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2,
|
|
LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
|
|
|
|
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_LOW);
|
|
|
|
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_NORMAL);
|
|
|
|
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);
|
|
|
|
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);
|
|
|
|
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
|
|
|
|
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MDATAALIGN_BYTE);
|
|
|
|
/* USART1 interrupt Init */
|
|
NVIC_SetPriority(USART1_IRQn, 0);
|
|
NVIC_EnableIRQ(USART1_IRQn);
|
|
|
|
/* USER CODE BEGIN USART1_Init 1 */
|
|
|
|
/* USER CODE END USART1_Init 1 */
|
|
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
|
|
USART_InitStruct.BaudRate = 115200;
|
|
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
|
|
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
|
|
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
|
|
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
|
|
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
|
|
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
|
|
LL_USART_Init(USART1, &USART_InitStruct);
|
|
LL_USART_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
|
|
LL_USART_SetRXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
|
|
LL_USART_DisableFIFO(USART1);
|
|
LL_USART_ConfigAsyncMode(USART1);
|
|
|
|
/* USER CODE BEGIN WKUPType USART1 */
|
|
|
|
/* USER CODE END WKUPType USART1 */
|
|
|
|
LL_USART_Enable(USART1);
|
|
|
|
/* Polling USART1 initialisation */
|
|
while ((!(LL_USART_IsActiveFlag_TEACK(USART1))) ||
|
|
(!(LL_USART_IsActiveFlag_REACK(USART1)))) {
|
|
}
|
|
/* USER CODE BEGIN USART1_Init 2 */
|
|
usart1_hart_init();
|
|
/* USER CODE END USART1_Init 2 */
|
|
}
|
|
/* USART2 init function */
|
|
|
|
void MX_USART2_UART_Init(void) {
|
|
|
|
/* USER CODE BEGIN USART2_Init 0 */
|
|
|
|
/* USER CODE END USART2_Init 0 */
|
|
|
|
LL_USART_InitTypeDef USART_InitStruct = {0};
|
|
|
|
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
|
|
|
/* Peripheral clock enable */
|
|
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);
|
|
|
|
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
|
|
/**USART2 GPIO Configuration
|
|
PA2 ------> USART2_TX
|
|
PA3 ------> USART2_RX
|
|
*/
|
|
GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
|
|
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
|
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
|
|
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
|
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
|
|
GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
|
|
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
|
|
|
GPIO_InitStruct.Pin = LL_GPIO_PIN_3;
|
|
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
|
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
|
|
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
|
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
|
|
GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
|
|
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
|
|
|
/* USART2 DMA Init */
|
|
|
|
/* USART2_RX Init */
|
|
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_3, LL_DMAMUX_REQ_USART2_RX);
|
|
|
|
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3,
|
|
LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
|
|
|
|
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PRIORITY_LOW);
|
|
|
|
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MODE_NORMAL);
|
|
|
|
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PERIPH_NOINCREMENT);
|
|
|
|
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MEMORY_INCREMENT);
|
|
|
|
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_BYTE);
|
|
|
|
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_BYTE);
|
|
|
|
/* USART2_TX Init */
|
|
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_4, LL_DMAMUX_REQ_USART2_TX);
|
|
|
|
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4,
|
|
LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
|
|
|
|
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PRIORITY_LOW);
|
|
|
|
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MODE_NORMAL);
|
|
|
|
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PERIPH_NOINCREMENT);
|
|
|
|
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MEMORY_INCREMENT);
|
|
|
|
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PDATAALIGN_BYTE);
|
|
|
|
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MDATAALIGN_BYTE);
|
|
|
|
/* USART2 interrupt Init */
|
|
NVIC_SetPriority(USART2_IRQn, 0);
|
|
NVIC_EnableIRQ(USART2_IRQn);
|
|
|
|
/* USER CODE BEGIN USART2_Init 1 */
|
|
|
|
/* USER CODE END USART2_Init 1 */
|
|
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
|
|
USART_InitStruct.BaudRate = 115200;
|
|
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
|
|
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
|
|
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
|
|
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
|
|
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
|
|
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
|
|
LL_USART_Init(USART2, &USART_InitStruct);
|
|
LL_USART_ConfigAsyncMode(USART2);
|
|
|
|
/* USER CODE BEGIN WKUPType USART2 */
|
|
|
|
/* USER CODE END WKUPType USART2 */
|
|
|
|
LL_USART_Enable(USART2);
|
|
|
|
/* Polling USART2 initialisation */
|
|
while ((!(LL_USART_IsActiveFlag_TEACK(USART2))) ||
|
|
(!(LL_USART_IsActiveFlag_REACK(USART2)))) {
|
|
}
|
|
/* USER CODE BEGIN USART2_Init 2 */
|
|
usart2_hart_init();
|
|
/* USER CODE END USART2_Init 2 */
|
|
}
|
|
|
|
/* USER CODE BEGIN 1 */
|
|
/**
|
|
* @brief Initializes USART1 for bidirectional communication using DMA.
|
|
* @note This function configures USART1 to operate in both transmit (TX) and
|
|
* receive (RX) modes. It sets up the DMA channels for data transfer,
|
|
* enables idle line interrupts to detect the end of data reception,
|
|
* and configures necessary settings for efficient data transmission and
|
|
* reception.
|
|
*
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void usart1_hart_init(void) {
|
|
// Set USART1 to operate in TX and RX mode
|
|
LL_USART_SetTransferDirection(USART1, LL_USART_DIRECTION_TX_RX);
|
|
|
|
// Enable idle line interrupt for USART1 to detect when data reception is
|
|
// complete
|
|
LL_USART_EnableIT_IDLE(USART1);
|
|
|
|
/* Configure DMA for USART1 RX */
|
|
// Set the peripheral address for DMA RX to the USART1 data register
|
|
LL_DMA_SetPeriphAddress(
|
|
DMA1, LL_DMA_CHANNEL_1,
|
|
LL_USART_DMA_GetRegAddr(USART1, LL_USART_DMA_REG_DATA_RECEIVE));
|
|
// Set the memory address where received data will be stored
|
|
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1,
|
|
(uint32_t)g_uart_in_rx_buf[g_uart_in_rx_index]);
|
|
// Set the amount of data to be received
|
|
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, BUFFER_SIZE);
|
|
|
|
/* Enable DMA transfer complete and transfer error interrupts for RX */
|
|
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
|
|
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_1);
|
|
|
|
/* Start the DMA channel for USART1 RX and enable USART RX DMA */
|
|
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
|
|
LL_USART_EnableDMAReq_RX(USART1);
|
|
// Clear any existing idle line flags
|
|
LL_USART_ClearFlag_IDLE(USART1);
|
|
|
|
/* Configure DMA for USART1 TX */
|
|
// Set the peripheral address for DMA TX to the USART1 data register
|
|
LL_DMA_SetPeriphAddress(
|
|
DMA1, LL_DMA_CHANNEL_2,
|
|
LL_USART_DMA_GetRegAddr(USART1, LL_USART_DMA_REG_DATA_TRANSMIT));
|
|
// Enable USART1 TX DMA request for data transmission
|
|
LL_USART_EnableDMAReq_TX(USART1);
|
|
// Enable DMA transfer complete interrupt for USART1 TX
|
|
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2);
|
|
}
|
|
|
|
/**
|
|
* @brief Initializes USART2 for bidirectional communication using DMA.
|
|
* @note This function configures USART2 to operate in both transmit (TX) and
|
|
* receive (RX) modes. It sets up the DMA channels for data transfer,
|
|
* enables idle line interrupts to signal the end of data reception,
|
|
* and configures necessary settings for effective data transmission and
|
|
* reception.
|
|
*
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void usart2_hart_init(void) {
|
|
// Set USART2 to operate in TX and RX mode
|
|
LL_USART_SetTransferDirection(USART2, LL_USART_DIRECTION_TX_RX);
|
|
|
|
// Enable idle line interrupt for USART2 to detect the end of data reception
|
|
LL_USART_EnableIT_IDLE(USART2);
|
|
|
|
/* Configure DMA for USART2 RX */
|
|
// Set the peripheral address for DMA RX to the USART2 data register
|
|
LL_DMA_SetPeriphAddress(
|
|
DMA1, LL_DMA_CHANNEL_3,
|
|
LL_USART_DMA_GetRegAddr(USART2, LL_USART_DMA_REG_DATA_RECEIVE));
|
|
// Set the memory address for storing the received data
|
|
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_3,
|
|
(uint32_t)g_uart_out_rx_buf[g_uart_out_rx_index]);
|
|
// Set the amount of data to be received
|
|
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_3, BUFFER_SIZE);
|
|
|
|
/* Enable DMA transfer complete and transfer error interrupts for RX */
|
|
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_3);
|
|
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_3);
|
|
|
|
/* Start the DMA channel for USART2 RX and enable USART RX DMA */
|
|
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_3);
|
|
LL_USART_EnableDMAReq_RX(USART2);
|
|
// Clear any existing idle line flags
|
|
LL_USART_ClearFlag_IDLE(USART2);
|
|
|
|
/* Configure DMA for USART2 TX */
|
|
// Set the peripheral address for DMA TX to the USART2 data register
|
|
LL_DMA_SetPeriphAddress(
|
|
DMA1, LL_DMA_CHANNEL_4,
|
|
LL_USART_DMA_GetRegAddr(USART2, LL_USART_DMA_REG_DATA_TRANSMIT));
|
|
// Enable USART2 TX DMA request for data transmission
|
|
LL_USART_EnableDMAReq_TX(USART2);
|
|
// Enable DMA transfer complete interrupt for USART2 TX
|
|
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_4);
|
|
}
|
|
|
|
/**
|
|
* @brief Queue data for DMA transmission on USART1.
|
|
*
|
|
* This function always enqueues the data first.
|
|
* If the DMA is idle, it immediately starts transmission.
|
|
* If the queue is full, the packet is discarded.
|
|
*
|
|
* @param buf Pointer to the data buffer.
|
|
* @param size Number of bytes to transmit.
|
|
*/
|
|
void usart1_transmit_dma(uint8_t *buf, uint16_t size)
|
|
{
|
|
__disable_irq(); // Enter critical section
|
|
|
|
if (tx_in_buffer.packet_count < MAX_QUEUE_SIZE && size <= BUFFER_SIZE) {
|
|
// Copy data into the queue
|
|
memcpy(tx_in_buffer.send_queue[tx_in_buffer.tail].data, buf, size);
|
|
tx_in_buffer.send_queue[tx_in_buffer.tail].length = size;
|
|
|
|
// Advance tail and increment count
|
|
tx_in_buffer.tail = (tx_in_buffer.tail + 1) % MAX_QUEUE_SIZE;
|
|
tx_in_buffer.packet_count++;
|
|
|
|
// If DMA is idle, start transmission
|
|
if (g_uart_in_transmit_complete) {
|
|
uint8_t index = tx_in_buffer.head;
|
|
uint16_t len = tx_in_buffer.send_queue[index].length;
|
|
|
|
g_uart_in_transmit_complete = 0;
|
|
|
|
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)tx_in_buffer.send_queue[index].data);
|
|
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, len);
|
|
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
|
|
}
|
|
} else {
|
|
// Queue full, discard the packet
|
|
// Optional: increment a counter or log the event
|
|
}
|
|
|
|
__enable_irq(); // Exit critical section
|
|
}
|
|
|
|
/**
|
|
* @brief Queue data for DMA transmission on USART2.
|
|
*
|
|
* This function always enqueues the data first.
|
|
* If the DMA is idle, it immediately starts transmission.
|
|
* If the queue is full, the packet is discarded.
|
|
*
|
|
* @param buf Pointer to the data buffer.
|
|
* @param size Number of bytes to transmit.
|
|
*/
|
|
void usart2_transmit_dma(uint8_t *buf, uint16_t size)
|
|
{
|
|
__disable_irq(); // Enter critical section
|
|
|
|
if (tx_out_buffer.packet_count < MAX_QUEUE_SIZE && size <= BUFFER_SIZE) {
|
|
// Copy data into the queue
|
|
memcpy(tx_out_buffer.send_queue[tx_out_buffer.tail].data, buf, size);
|
|
tx_out_buffer.send_queue[tx_out_buffer.tail].length = size;
|
|
|
|
// Advance tail and increment count
|
|
tx_out_buffer.tail = (tx_out_buffer.tail + 1) % MAX_QUEUE_SIZE;
|
|
tx_out_buffer.packet_count++;
|
|
|
|
// If DMA is idle, start transmission
|
|
if (g_uart_out_transmit_complete) {
|
|
uint8_t index = tx_out_buffer.head;
|
|
uint16_t len = tx_out_buffer.send_queue[index].length;
|
|
|
|
g_uart_out_transmit_complete = 0;
|
|
|
|
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4, (uint32_t)tx_out_buffer.send_queue[index].data);
|
|
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, len);
|
|
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
|
|
}
|
|
} else {
|
|
// Queue full, discard the packet
|
|
// Optional: increment a counter or log the event
|
|
}
|
|
|
|
__enable_irq(); // Exit critical section
|
|
}
|
|
|
|
/* USER CODE END 1 */
|