42. LED toggle using SPI

Back To All Submissions
Previous Submission
Next Submission

Solving Approach

How do you plan to solve it?

 

 

Code

/*
 * my_main.c
 *
 *  Created on: Mar 14, 2026
 *      Author: georgegio
 */

#include "my_main.h"

DMA_HandleTypeDef dma_usart2_tx;
UART_HandleTypeDef usart2;
SPI_HandleTypeDef spi1;
GPIO_InitTypeDef button, sspin;
uint8_t toggle = 0, change_val = 0;
char buffer[50] = { 0 };

int main(void)
{
	/* Initializes low level hardware at the processor level */
	HAL_Init();

	// Sets other clock sources besides HSI
	if( SystemClock_Config(HSI_16) != Execution_Succesfull)
		return Execution_Failed;

	// Configure the I2C module.
	if ( SPI_Config(&spi1, SPI1, MASTER) != Execution_Succesfull )
		return Execution_Failed;

	// Configure the Button
	if( BUTTON_Config(&button) != Execution_Succesfull )
		return Execution_Failed;

	// Configure the SS GPIO pin for SPI communication
	if( SPI_SS_Config(&sspin) != Execution_Succesfull)
		return Execution_Failed;

	// Configure the DMA1 module
	if( DMA_Config() != Execution_Succesfull )
		return Execution_Failed;

	// Configure the USART1 module
	if( USART2_Config(&usart2) != Execution_Succesfull )
		return Execution_Failed;

	for(;;)
	{
		if(change_val)
		{
			// Initialize the SPI transfer
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
			if( HAL_SPI_Transmit(&spi1, &toggle, 1, HAL_MAX_DELAY) != HAL_OK )
				for(;;);
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
			sprintf(buffer, "Toggle Value: %d \n\r", toggle);
			if( HAL_UART_Transmit_DMA(&usart2, (const uint8_t *)buffer, sizeof(buffer)) != HAL_OK )
				for(;;);
			//memset(buffer, 0, sizeof(buffer));

			change_val = 0;
		}
	}

	return Execution_Succesfull;
}

ReturnStatus SystemClock_Config(Clock_Source_t clk)
{
	RCC_OscInitTypeDef osc_init;
	RCC_ClkInitTypeDef clk_init;

	memset(&osc_init, 0, sizeof(osc_init));
	memset(&clk_init, 0, sizeof(clk_init));

	switch (clk)
	{
		case HSI_16:
			break;
		case HSI_8:
			osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSI;
			osc_init.HSIState = RCC_HSI_ON;
			if ( HAL_RCC_OscConfig(&osc_init) != HAL_OK )
				return Execution_Failed;

			clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
			clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
			clk_init.AHBCLKDivider = RCC_SYSCLK_DIV2;
			clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
			clk_init.APB2CLKDivider = RCC_HCLK_DIV1;

			if ( HAL_RCC_ClockConfig(&clk_init, FLASH_ACR_LATENCY_0WS) != HAL_OK )
				return Execution_Failed;
			break;

		case HSE_4:
			osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
			osc_init.HSEState = RCC_HSE_ON; // YOU HAVE TO CHECK ON THE SCHEMATIC WHETHER HSE IS BYPASSED OR NOT!!!
			if ( HAL_RCC_OscConfig(&osc_init) != HAL_OK )
				return Execution_Failed;

			clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
			clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
			clk_init.AHBCLKDivider = RCC_SYSCLK_DIV2;
			clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
			clk_init.APB2CLKDivider = RCC_HCLK_DIV2;

			if ( HAL_RCC_ClockConfig(&clk_init, FLASH_ACR_LATENCY_0WS) != HAL_OK )
				return Execution_Failed;

			__HAL_RCC_HSI_DISABLE(); //Disable HSI to reduce Power Consumption.

			break;

		case HSE_2:
				osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
				osc_init.HSEState = RCC_HSE_ON; // YOU HAVE TO CHECK ON THE SCHEMATIC WHETHER HSE IS BYPASSED OR NOT!!!
				if ( HAL_RCC_OscConfig(&osc_init) != HAL_OK )
					return Execution_Failed;

				clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
				clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
				clk_init.AHBCLKDivider = RCC_SYSCLK_DIV4;
				clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
				clk_init.APB2CLKDivider = RCC_HCLK_DIV2;

				if ( HAL_RCC_ClockConfig(&clk_init, FLASH_ACR_LATENCY_0WS) != HAL_OK )
					return Execution_Failed;

				__HAL_RCC_HSI_DISABLE(); //Disable HSI to reduce Power Consumption.

				break;

		case PLL_84:
#if !NO_PLL
				osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
				osc_init.HSEState = RCC_HSE_ON;

				// Enable the clock to the power ccontroller.
				__HAL_RCC_PWR_CLK_ENABLE();

				// Set regulator voltage scale as 1.
				__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

				// Turn on the over drive mode.

				osc_init.PLL.PLLState = RCC_PLL_ON;
				osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE;
				osc_init.PLL.PLLM = 16;
				osc_init.PLL.PLLN = 336;
				osc_init.PLL.PLLP = 2;
				osc_init.PLL.PLLQ = 7;

				if ( HAL_RCC_OscConfig(&osc_init) != HAL_OK )
					return Execution_Failed;

				clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
				clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
				clk_init.AHBCLKDivider = RCC_SYSCLK_DIV2;
				clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
				clk_init.APB2CLKDivider = RCC_HCLK_DIV2;

				if ( HAL_RCC_ClockConfig(&clk_init, FLASH_ACR_LATENCY_0WS) != HAL_OK )
					return Execution_Failed;

				__HAL_RCC_HSI_DISABLE(); //Disable HSI to reduce Power Consumption.

				break;
#endif
		case PLL_42:
#if !NO_PLL
				osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
				osc_init.HSEState = RCC_HSE_ON;

				// Enable the clock to the power ccontroller.
				__HAL_RCC_PWR_CLK_ENABLE();

				// Set regulator voltage scale as 1.
				__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

				// Turn on the over drive mode.

				osc_init.PLL.PLLState = RCC_PLL_ON;
				osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE;
				osc_init.PLL.PLLM = 16;
				osc_init.PLL.PLLN = 336;
				osc_init.PLL.PLLP = 2;
				osc_init.PLL.PLLQ = 7;

				if ( HAL_RCC_OscConfig(&osc_init) != HAL_OK )
					return Execution_Failed;

				clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
				clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
				clk_init.AHBCLKDivider = RCC_SYSCLK_DIV4;
				clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
				clk_init.APB2CLKDivider = RCC_HCLK_DIV2;

				if ( HAL_RCC_ClockConfig(&clk_init, FLASH_ACR_LATENCY_0WS) != HAL_OK )
					return Execution_Failed;

				__HAL_RCC_HSI_DISABLE(); //Disable HSI to reduce Power Consumption.

				break;
#endif
		default:
	}

	return Execution_Succesfull;
}

ReturnStatus BUTTON_Config(GPIO_InitTypeDef *button)
{
	memset(button, 0, sizeof(*button));

	// Enable the clock to GPIOA
	__HAL_RCC_GPIOB_CLK_ENABLE();

	button->Pin = GPIO_PIN_0;
	button->Speed = GPIO_SPEED_FREQ_LOW;
	button->Pull = GPIO_PULLUP;
	button->Mode = GPIO_MODE_IT_FALLING;

	HAL_GPIO_Init(GPIOB, button);

	HAL_NVIC_EnableIRQ(EXTI0_IRQn);
	HAL_NVIC_SetPriority(EXTI0_IRQn, 10, 0);

	return Execution_Succesfull;
}

ReturnStatus SPI_SS_Config(GPIO_InitTypeDef *sspin)
{
	memset(sspin, 0, sizeof(*sspin));

	// Enable the clock to GPIOA
	__HAL_RCC_GPIOB_CLK_ENABLE();

	sspin->Pin = GPIO_PIN_1;
	sspin->Speed = GPIO_SPEED_FREQ_LOW;
	sspin->Pull = GPIO_PULLUP;
	sspin->Mode = GPIO_MODE_OUTPUT_PP;

	HAL_GPIO_Init(GPIOB, sspin);

	return Execution_Succesfull;
}

ReturnStatus SPI_Config(SPI_HandleTypeDef *spi, SPI_TypeDef *Instance, PURPOSE role)
{
	memset(spi, 0, sizeof(*spi));

	spi->Instance = Instance;
	spi->Init.Mode = (role == MASTER) ? SPI_MODE_MASTER : SPI_MODE_SLAVE;
	spi->Init.Direction = SPI_DIRECTION_2LINES;
	spi->Init.DataSize = SPI_DATASIZE_8BIT;
	spi->Init.CLKPolarity = SPI_POLARITY_HIGH;
	spi->Init.CLKPhase = SPI_PHASE_1EDGE;
	spi->Init.NSS = SPI_NSS_SOFT;
	if(role == MASTER)
		spi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
	spi->Init.FirstBit = SPI_FIRSTBIT_MSB;
	spi->Init.TIMode = SPI_TIMODE_DISABLE;
	spi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

	if( HAL_SPI_Init(spi) != HAL_OK)
		return Execution_Failed;

	return Execution_Succesfull;
}

ReturnStatus DMA_Config(void)
{
	// Enable the clock for DMA1
	__HAL_RCC_DMA1_CLK_ENABLE();

	// Enable the interrupt of DMA1_Stream6 and set its priority
	HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
	HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);

	return Execution_Succesfull;
}

ReturnStatus USART2_Config(UART_HandleTypeDef *uart_handle)
{
	memset(uart_handle, 0, sizeof(*uart_handle));

	uart_handle->Instance = USART2;
	uart_handle->Init.BaudRate = 115200;
	uart_handle->Init.HwFlowCtl = UART_HWCONTROL_NONE;
	uart_handle->Init.Mode = UART_MODE_TX;
	uart_handle->Init.OverSampling = UART_OVERSAMPLING_16;
	uart_handle->Init.Parity = UART_PARITY_NONE;
	uart_handle->Init.StopBits = UART_STOPBITS_1;
	uart_handle->Init.WordLength = UART_WORDLENGTH_8B;

	if( HAL_UART_Init(uart_handle) != HAL_OK )
		return Execution_Failed;

	return Execution_Succesfull;

}

void Delay(uint32_t ms)
{
	DWT->CTRL |= (1 << 0); // Enable the DTW counter of the CortexM4
	uint32_t start = DWT->CYCCNT;
	uint32_t ticks = ms * (HAL_RCC_GetHCLKFreq() / 1000);

	while ((DWT->CYCCNT - start) < ticks);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	toggle = toggle ^ 1;
	change_val = 1;
}
/*
 * msp.c
 *
 *  Created on: Mar 14, 2026
 *      Author: georgegio
 */

#include "my_main.h"

extern DMA_HandleTypeDef dma_usart2_tx;

void HAL_MspInit(void)
{

	HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

	// Enable necessary IRQs
	HAL_NVIC_SetPriority(MemoryManagement_IRQn, 0, 0);
	HAL_NVIC_SetPriority(BusFault_IRQn, 0, 0);
	HAL_NVIC_SetPriority(UsageFault_IRQn, 0, 0);

	HAL_NVIC_EnableIRQ(MemoryManagement_IRQn);
	HAL_NVIC_EnableIRQ(BusFault_IRQn);
	HAL_NVIC_EnableIRQ(UsageFault_IRQn);

}

void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
	UNUSED(hspi);
	GPIO_InitTypeDef gpio_spi;

	memset(&gpio_spi, 0, sizeof(gpio_spi));

	// Enable the SPI and GPIO PORT A clock.
	__HAL_RCC_SPI1_CLK_ENABLE();
	__HAL_RCC_GPIOA_CLK_ENABLE();

	gpio_spi.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
	gpio_spi.Mode = GPIO_MODE_AF_PP;
	gpio_spi.Pull = GPIO_NOPULL;
	gpio_spi.Speed = GPIO_SPEED_FREQ_LOW;
	gpio_spi.Alternate = GPIO_AF5_SPI1;

	HAL_GPIO_Init(GPIOA,  &gpio_spi);

	/*HAL_NVIC_EnableIRQ(SPI1_IRQn);
	HAL_NVIC_EnableIRQ(SPI1_IRQn);*/
}

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
	GPIO_InitTypeDef gpio_uart;

	memset(&gpio_uart, 0, sizeof(gpio_uart));

	// Enable the UART and GPIO PORTB clock.
	__HAL_RCC_USART2_CLK_ENABLE();
	__HAL_RCC_GPIOA_CLK_ENABLE();

	gpio_uart.Pin = GPIO_PIN_2 | GPIO_PIN_3;
	gpio_uart.Speed = GPIO_SPEED_FREQ_LOW;
	gpio_uart.Mode = GPIO_MODE_AF_PP;
	gpio_uart.Alternate = GPIO_AF7_USART2;
	gpio_uart.Pull = GPIO_PULLUP;

	HAL_GPIO_Init(GPIOA, &gpio_uart);

	HAL_NVIC_EnableIRQ(USART2_IRQn);
	HAL_NVIC_EnableIRQ(USART2_IRQn);

	memset(&dma_usart2_tx, 0, sizeof(dma_usart2_tx));

	dma_usart2_tx.Instance = DMA1_Stream6;
	dma_usart2_tx.Init.Channel = DMA_CHANNEL_4;
	dma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
	dma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
	dma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
	dma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
	dma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
	dma_usart2_tx.Init.Mode = DMA_NORMAL;
	dma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
	dma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
	if (HAL_DMA_Init(&dma_usart2_tx) != HAL_OK)
	{
	  for(;;);
	}

	__HAL_LINKDMA(huart,hdmatx,dma_usart2_tx);
}


/*
 * it.c
 *
 *  Created on: Mar 14, 2026
 *      Author: georgegio
 */
#include "my_main.h"

extern DMA_HandleTypeDef dma_usart2_tx;
extern UART_HandleTypeDef usart2;

void SysTick_Handler(void)
{
	HAL_IncTick();
	HAL_SYSTICK_IRQHandler();
}

void EXTI0_IRQHandler(void)
{
	Delay(30); // Delay 50ms
	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}

void DMA1_Stream6_IRQHandler(void)
{
	HAL_DMA_IRQHandler(&dma_usart2_tx);
}

void USART2_IRQHandler(void)
{
	HAL_UART_IRQHandler(&usart2);
}

void SPI1_IRQHandler(void)
{
	for(;;);
}

void HardFault_Handler(void)
{
	// Halt execution, when HardFault error occurs.
	for(;;);
}

void MemManage_Handler(void)
{
	// Halt execution, when MemManage error occurs.
	for(;;);
}

void BusFault_Handler(void)
{
	// Halt execution, when BusFault error occurs.
	for(;;);
}

void UsageFault_Handler(void)
{
	// Halt execution, when UsageFault error occurs.
	for(;;);
}

Output

Video

Add a video of the output (know more)

 

 

 

 

 

Photo of Output

Add a photo of your hardware showing the output.


 

Was this helpful?
Upvote
Downvote