Question
UART DMA &SPI DMA and Semaphore Mutex issue
Hello,
I am trying to send a message using SPI DMA. I also enabled UART DMA. When both of them are executing, SPI DMA does not work. I implemented SEmaphore Mutex as well. Below are my code and SPI and UART drivers. Can anyone help me
---------------------------------------------------------------------main.c---------------------------------------------------------------------------
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @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 "main.h"
#include "cmsis_os.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "GPIO.h"
#include "UART.h"
#include "SPI.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* Definitions for defaultTask */
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void GPIOA_Init(void);
void UART_Init(void);
void UART2_Tx_DMA_Init(void * SrcAddr, uint16_t dataSize);
void SPI_Init(void);
void SPI1_Tx_DMA_Init(void * SrcAddr, uint16_t dataSize);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
SemaphoreHandle_t xRecursiveMutex;
//void UART_Task(void *pvParameters);
void SPI_Task(void *pvParameters);
void LED_Blinking_Task(void *pvParameters);
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
/* USER CODE BEGIN 2 */
xRecursiveMutex = xSemaphoreCreateMutex();
/*xTaskCreate(UART_Task,
"UART&DMA",
128,
NULL,
1,
NULL);
*/
xTaskCreate(SPI_Task,
"SPI&DMA",
128,
NULL,
1,
NULL);
xTaskCreate(LED_Blinking_Task,
"LED_Blinking",
128,
NULL,
1,
NULL);
vTaskStartScheduler();
/* USER CODE END 2 */
/* Init scheduler */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* creation of defaultTask */
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_EVENTS */
/* add events, ... */
/* USER CODE END RTOS_EVENTS */
/* Start scheduler */
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
---------------------------------------------------------------------SPI.c---------------------------------------------------------------------------
#include "stm32f4xx.h"
#include "SPI.h"
#include "UART.h"
void SPI_Init(void)
{
// Clock GPIOA was enabled in UART driver
// Enable GPIOB clock
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
// Enable SPI1 clock
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
//Enable DMA Clock
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
// Configure GPIOA5,6,7 and GPIOB6 as Alternate Function Mode
GPIOB->MODER &= 0x00000000;
GPIOA->MODER |= (2U << 10) | (2U << 12) | (2U << 14); // Set PA5,6,7 to AF mode
GPIOB->MODER |= (1U << 12); // Set PB6 to general output mode as Chip Select
GPIOB->BSRR = (1U << 6); // Set PB6 high (CS idle)
// Configure PA5,6,7 as very High Speed and PB6 as High Speed
GPIOA->OSPEEDR |= (3U << 10) | (3U << 12) | (3U << 14);
GPIOB->OSPEEDR |= (2U << 12);
//Set PB6 as Pull-Down
GPIOB->PUPDR |= (2U << 12);
// Configure AF5 (SPI1) for PA5,6,7
GPIOA->AFR[0] &= ~((0xF << (5 * 4)) | (0xF << (6 * 4)) | (0xF << (7 * 4))); // Clear PA5,6,7 AF bits
GPIOA->AFR[0] |= ((0x5 << (5 * 4)) | (0x5 << (6 * 4)) | (0x5 << (7 * 4))); // Set PA5,6,7 to AF5
// Configure SPI1
SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_DFF | SPI_CR1_BR_0; // Master mode, software NSS, 16-bit, baud rate
SPI1->CR2 = SPI_CR2_TXDMAEN; // Enable TX DMA
SPI1->CR1 |= SPI_CR1_SPE; // Enable SPI1
}
void SPI1_Tx_DMA_Init(void * SrcAddr, uint16_t dataSize)
{
Print_Message((void *)"Start SPI DMA config\r\n", 30);
//Disable DMA stream for configuration
DMA2_Stream3->CR &= ~DMA_SxCR_EN;
// Wait for stream to be disabled
while (DMA2_Stream3->CR & DMA_SxCR_EN);
//Write o in LIFCR
DMA2->LIFCR &= ~(0xFFFFFFFF);
//Write 1 and clear in LIFCR related to stream3
DMA2->LIFCR = DMA_LIFCR_CDMEIF3 |
DMA_LIFCR_CTEIF3 |
DMA_LIFCR_CHTIF3 |
DMA_LIFCR_CTCIF3;
//Set the peripheral port register address
DMA2_Stream3->PAR = (uint32_t)&SPI1->DR;
// Set DMA stream priority
//DMA2_Stream3->CR |= DMA_SxCR_PL_1;
//Set the memory address.
//Later store ADC values to M0AR
DMA2_Stream3->M0AR = (uint32_t)SrcAddr;
//Total number of data items to be transferred
DMA2_Stream3->NDTR = dataSize;
// Configure DMA stream for SPI1 transmission (DMA2 Stream 3, Channel 3)
DMA2_Stream3->CR = (3U << DMA_SxCR_CHSEL_Pos)| // Select Channel 3 for USART2 TX
DMA_SxCR_MINC | // Enable memory increment mode
DMA_SxCR_DIR_0 | // Set direction: memory to peripheral
DMA_SxCR_TCIE |
DMA_SxCR_CIRC; // Enable transfer complete interrupt (Circular Mode)
//Enable DMA stream
DMA2_Stream3->CR |= DMA_SxCR_EN;
Print_Message((void *)"SPI DMA Enabled...\r\n", 30);
}
---------------------------------------------------------------------UART.c-------------------------------------------------------------------------
#include "stm32f4xx.h"
#include "UART.h"
void UART_Init(void)
{
// Enable GPIOA clock
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
// Enable USART2 clock
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
//Enable DMA Clock
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
// Configure PA2 (Tx) as Alternate Function Mode
GPIOA->MODER &= 0x00000000; // Clear MODER bits for PA GPIOs
GPIOA->MODER |= (2U << 4); // Set PA2 to AF mode
// Configure PA2 as High Speed
GPIOA->OSPEEDR |= (2U << 4);
// Configure AF7 (USART2) for PA2
GPIOA->AFR[0] &= ~(0xF << 8); // Clear PA2 AF bits
GPIOA->AFR[0] |= (0x7 << 8); // Set PA2 to AF7
// Configure USART2 parameters: 9600 baud, 8 data bits, 1 stop bit
USART2->BRR = 0x0683; // Baud rate 9600 (assuming 16MHz clock)
USART2->CR1 |= USART_CR1_TE; // Enable transmitter
USART2->CR1 |= USART_CR1_UE; // Enable USART
USART2->CR3 |= USART_CR3_DMAT; //Enable UART DMA
}
void UART2_Tx_DMA_Init(void * SrcAddr, uint16_t dataSize)
{
//Disable DMA stream for configuration
DMA1_Stream6->CR &= ~DMA_SxCR_EN;
// Wait for stream to be disabled
while(DMA1_Stream6->CR & DMA_SxCR_EN);
//Write o in HIFCR
DMA1->HIFCR &= ~(0xFFFFFFFF);
//Write 1 in HIFCR related to stream6
DMA1->HIFCR = DMA_HIFCR_CDMEIF6 |
DMA_HIFCR_CTEIF6 |
DMA_HIFCR_CHTIF6 |
DMA_HIFCR_CTCIF6;
//Set the peripheral port register address
DMA1_Stream6->PAR = (uint32_t)&USART2->DR;
//Set the memory address.
//Later store ADC values to M0AR
DMA1_Stream6->M0AR = (uint32_t)SrcAddr;
//Total number of data items to be transferred
DMA1_Stream6->NDTR = dataSize;
// Configure DMA stream for USART2 transmission (DMA1 Stream 6, Channel 4)
DMA1_Stream6->CR = (4U << DMA_SxCR_CHSEL_Pos)| // Select Channel 4 for USART2 TX
DMA_SxCR_MINC | // Enable memory increment mode
DMA_SxCR_DIR_0 | // Set direction: memory to peripheral
DMA_SxCR_TCIE |
DMA_SxCR_CIRC; // Enable transfer complete interrupt (Circular Mode)
//Enable DMA stream
DMA1_Stream6->CR |= DMA_SxCR_EN;
}
void Send_Data(char data)
{
while (!(USART2->SR & USART_SR_TXE)); // Wait until TXE is set
USART2->DR = data; // Transmit data
while (!(USART2->SR & USART_SR_TC)); // Wait until TC is set (transmission complete)
}
void Print_Message(void * SrcAddr, uint16_t dataSize)
{
// Failure message
const char *Failure_Msg = "Memory allocation failed\r\n";
// Define structure for data transmission
typedef struct
{
int Data_Size;
char Data[100];
} Data_Transmission;
// Allocate memory for the data structure
Data_Transmission *First_Data = malloc(sizeof(Data_Transmission));
if (First_Data == NULL)
{
// If memory allocation fails, send failure message
Split_Bits(Failure_Msg);
return;
}
// Initialize and prepare data for transmission
strcpy(First_Data->Data, SrcAddr);
//First_Data->Data_Size = strlen(First_Data->Data);
First_Data->Data_Size = dataSize;
// Send data via UART
Split_Bits(First_Data->Data);
// Free allocated memory
free(First_Data);
}
void Split_Bits(const char *ptr)
{
// Iterate through the string and send each character
while (*ptr != '\0')
{
Send_Data(*ptr++);
}
}
