Hello there,
I am trying to control 2 LED strips (one with a WS2811 LED driver and one with a USC512C4 LED driver) with my STM32L4 with integrated RS485.
Do you have any idea how to do this?
Best regard.
P.Congré
Hello there,
I am trying to control 2 LED strips (one with a WS2811 LED driver and one with a USC512C4 LED driver) with my STM32L4 with integrated RS485.
Do you have any idea how to do this?
Best regard.
P.Congré
I should have added that there's also useful material about DMX512 here on the community. Here are a couple of good examples from shabaz and from genebren
DMX Explained; DMX512 and RS-485 Protocol Detail for Lighting Applications
DMX diagnostic tool - Getting started
DMX diagnostic tool - Sending and Receiving Data
Hello Jon,
I managed to control my LED strip with the USC512C4 IC with my arduino, but I need to do it with my STM32L4 but I can't find anywhere how to do it.
Do you have a code example for an STM32L4?
Best regard.
P.Congré
genebren wrote:
... If you have the proper experience you should be able to find all you need to know from the documentation available from STM to take the concepts that you used on the Arduino and port them to the STM part.
Porting existing knowing-to-work code to the platform you're learning is an excellent way to get the experience.
You have the luxury to see everything working and know that there's no defects. When stuck, you can always go back to the working example and compare.
I've written a blog here on my approach to port a library between platforms. I'll search for it ...
edit: found: Educational BoosterPack and Hercules LaunchPad: LCD Driver - Part 3: SPI Works
Hello Gene
1) my code :
DMX.c
/*
* dmx.c
*
* Created on: 8 nov. 2021
* Author: Paul_C
*/
#include "main.h"
#include "dmx.h"
extern TIM_HandleTypeDef htim2;
extern TIM_HandleTypeDef htim15;
volatile static uint16_t slots_sent;
volatile static uint16_t slots_count;
volatile static const uint8_t *slots_ptr;
void dmx_send(const uint8_t *slots, uint16_t size)
{
/* Setup global variables, they will be accessed from interrupts */
slots_ptr = slots;
slots_sent = 0;
slots_count = size;
/*
* DMX512 packet starts with Reset Sequence. Reset Sequence starts with
* Break (low level), so set pin to output low.
*/
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);
/*
* Waiting for Break time, and everything further, is done through TIM3
* interrupt. At first interrupt (CC1) this timer changes pin to high
* for MarkAfterBreak. Then, in update interrupt, it configures pin into
* floating mode. Right after this, it sends first DMX byte 0x00, and
* turn on second timer for sending slots after MarkBetween slots.
*/
/* So, enable this timer */
__HAL_TIM_ENABLE(&htim15);
/* Wait until transmission of whole DMX packet is finished */
while (slots_ptr != NULL) {};
}
/* Interrupt handler for sending next slot (from TIM2 interrupt) */
void dmx_slot(void)
{
/*
* Each slot is sent in Update Interrupt of TIM2. So, period of TIM2 is
* time, needed for 11bits of slot (44us) and Mark Between Slots (0..1s)
*/
if (slots_sent < slots_count)
USART1->TDR = slots_ptr[slots_sent++];
else {
/* Stop timer when all slots are sent */
TIM2->CR1 &= ~(TIM_CR1_CEN);
TIM2->CNT = 0;
/* Indicate that transmission finished */
slots_ptr = NULL;
}
}
/* Interrupt handler for sending reset sequence (from TIM3 interrupt) */
void dmx_reset_sequence(void)
{
if (TIM15->SR & TIM_IT_UPDATE)
{
/* Reset sequence finished, stop timer */
TIM15->CR1 &= ~(TIM_CR1_CEN);
TIM15->CNT = 0;
/* Send start code 0x00 */
USART1->TDR = 0x00;
/* Start timer for sending slots */
__HAL_TIM_ENABLE(&htim2);
}
else if (TIM15->SR & TIM_IT_CC1)
{
/* Break end, set floating ping mode for Mark After Break */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
}
DMX.h
#ifndef INC_DMX_H_
#define INC_DMX_H_
#define DMX_BREAK 92
#define DMX_MAB 12
#define DMX_SLOT 44
#define DMX_MBS 0
void dmx_send(const uint8_t *slots, uint16_t size);
void dmx_slot(void);
void dmx_reset_sequence(void);
main.c
the first main i done
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "dmx.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
//#define USEC_COUNT (95/2)
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim15;
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_TIM2_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_TIM15_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
int i;
/* 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 */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_TIM15_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(0.080);
HAL_UART_Transmit(&huart1, 0x00, 100, 100);
for(i = 0; i <= 513; i++){
HAL_UART_Transmit(&huart1, 255, 100, 100);
i++;
}
HAL_UART_Transmit(&huart1, 0xFF, 100, 100);
i = 0;
HAL_Delay(0.012);
HAL_Delay(200);
}
/*if(dmx_sent) {
dmx_sent = 0;
packetizer_tick(&uasrt1_pactetizer);*/
/* 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};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = 0;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 40;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
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
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 4294967295;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
/**
* @brief TIM15 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM15_Init(void)
{
/* USER CODE BEGIN TIM15_Init 0 */
/* USER CODE END TIM15_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
/* USER CODE BEGIN TIM15_Init 1 */
/* USER CODE END TIM15_Init 1 */
htim15.Instance = TIM15;
htim15.Init.Prescaler = 0;
htim15.Init.CounterMode = TIM_COUNTERMODE_UP;
htim15.Init.Period = 65535;
htim15.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim15.Init.RepetitionCounter = 0;
htim15.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim15) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim15, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim15) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim15, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim15, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM15_Init 2 */
/* USER CODE END TIM15_Init 2 */
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 250000;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_2;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_RS485Ex_Init(&huart1, UART_DE_POLARITY_HIGH, 0, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* @brief USART2 Initialization Function
* @param None
* @retval None
*/
static void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
/* USER CODE END USART2_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, SMPS_EN_Pin|SMPS_V1_Pin|SMPS_SW_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : B1_Pin */
GPIO_InitStruct.Pin = B1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : SMPS_EN_Pin SMPS_V1_Pin SMPS_SW_Pin */
GPIO_InitStruct.Pin = SMPS_EN_Pin|SMPS_V1_Pin|SMPS_SW_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : SMPS_PG_Pin */
GPIO_InitStruct.Pin = SMPS_PG_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(SMPS_PG_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : LD4_Pin */
GPIO_InitStruct.Pin = LD4_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD4_GPIO_Port, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
the second one
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "dmx.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define USEC_COUNT (95/2)
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim15;
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_TIM2_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_TIM15_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
int i;
/* 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 */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_TIM15_Init();
/* USER CODE BEGIN 2 */
uint8_t test_packet[512];
for (int i=0; i<sizeof(test_packet); i++)
test_packet[i] = i & 0xFF;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
dmx_send(test_packet, sizeof(test_packet));
HAL_Delay(1000);
}
/* 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};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = 0;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 40;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
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
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 4294967295;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
/**
* @brief TIM15 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM15_Init(void)
{
/* USER CODE BEGIN TIM15_Init 0 */
/* USER CODE END TIM15_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
/* USER CODE BEGIN TIM15_Init 1 */
/* USER CODE END TIM15_Init 1 */
htim15.Instance = TIM15;
htim15.Init.Prescaler = 0;
htim15.Init.CounterMode = TIM_COUNTERMODE_UP;
htim15.Init.Period = 65535;
htim15.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim15.Init.RepetitionCounter = 0;
htim15.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim15) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim15, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim15) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim15, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim15, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM15_Init 2 */
/* USER CODE END TIM15_Init 2 */
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 250000;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_2;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_RS485Ex_Init(&huart1, UART_DE_POLARITY_HIGH, 0, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* @brief USART2 Initialization Function
* @param None
* @retval None
*/
static void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
/* USER CODE END USART2_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, SMPS_EN_Pin|SMPS_V1_Pin|SMPS_SW_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : B1_Pin */
GPIO_InitStruct.Pin = B1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : SMPS_EN_Pin SMPS_V1_Pin SMPS_SW_Pin */
GPIO_InitStruct.Pin = SMPS_EN_Pin|SMPS_V1_Pin|SMPS_SW_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : SMPS_PG_Pin */
GPIO_InitStruct.Pin = SMPS_PG_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(SMPS_PG_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : LD4_Pin */
GPIO_InitStruct.Pin = LD4_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD4_GPIO_Port, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
2) There is a diagram block of the instalation
3) i use the USART1 of my STM32L412 on the pin PA10 for the RX and PA9 for the TX
i also use 2 timer, timer2 internal clock input capture direct mode and the timer15 with the same configuration
To do that i use the ST's software, CUBEide and CUBEMX
P.Congré
Hello Paul,
OK, I see your code, and I think I understand what you are trying to do.
(For future reference, if you want to share some code the best way is to zip up the top level folder of the complete project (with all the cube files etc) and transfer it by Dropbox or whatever.
That way I could just run it - to get your code into a compileable form would take an hour or two - and that's a bit too long for me to do.)
A long time ago (2013) I wrote code for a DMX controller and a DMC controlled device.
void tx_dmx(uint8_t *data, uint32_t n) { // Timing according to DMX spec // 1 "SPACE" for BREAK - flexible, depends on time between bursts of data, min allowed 92uS // 2 "MARK" after break - min allowed is 12uS, we use 25uS; // 9 "MARK" between slots - min allowed is zero, we use 10uS // 10 "MARK" before break, min allowed is zer, we use 10uS // // we usually only send < 32 bytes so the total time taken is about 25 + (32 * ((11 * 4) + 10)) + 10 = 1763 uS // full length DMX frame would take 27737 uS which is OK occasionally but not good full time. // no need to use interrupts, we just block int d; if (n > DMX_MAX_TX) { n = DMX_MAX_TX; } GPIOA->MODER = (GPIOA->MODER & ~(3 << 18)) | (2 << 18); // set mode bits for A9 to 10 for UART // ends the break and starts the mark TIM2->CNT = 0; while (TIM2->CNT < MARK_AFTER_BREAK) {} for(d = 0; d < n; d++) { USART1->TDR = *data++; TIM2->CNT = 0; while (TIM2->CNT < MARK_BETWEEN_SLOTS + BYTE_TIME) {} } GPIOA->MODER = (GPIOA->MODER & ~(3 << 18)) | (1 << 18); // set mode bits for A9 to 01 for GPIO - DMX BREAK }
It blocks rather than use interrupts - not so slick but much easier to debug (because you can step through it one instruction at a time and measure pins with a DMM if that's all you have.)
I can post more of it if useful.
You will need a debugger (and to to do embedded code development you NEED a debugging tool). The ST Nucleo boards all have one built in. If you have your own board you can buy an ST Link for less than £20.
You will notice that I don't use the ST library code to controll USART and GPIO.
It might take a little longer to write the code at first but it does mean that you have to understand the peripherals - which is worth the hassle.
On a new project, especially if using using a new (to me) processor I usually put a "Blinky" and a hello world in the code.
SO it starts by blinking an LED (that tells me that the processor is running at the right speed) and uses the debug UART (there should always be a debug UART in any project where the processor has more than 28 pins)
to say "Project XX Build YY".
You might want to try these ideas on your project,
1) Get an LED blinking (so you can check timing - I've had a 200MHz uP almost working at 240MHz, took a long time to work out why the IO was flaky but nearly working)
2) Get used to looking at the peripheral registers with the debugger
3) Write your code so it is easy to step through
4) Expect to change code as you get stuff working, don't use interrupts at first unless you really have to, write blocking code, get it working, then apply the DMA and interrupts (and only if necessary).
5) (controversial) never trust the processor manufacturers library code, still less trust code you got free from the web, it can be very useful for getting ideas, learning stuff and so on - just don't count on it being good.
MK
Hello Michael,
I am using a nucleo-l412-rb-p for debugging.
I will try not to use the st library, it would be interesting for me if you could send more code examples.
P.Congré
Hello Paul,
I wouldn't change your code just yet, try stepping through and checking the peripheral settings as you go.
The ST GPIO stuff usually works OK but it's often slow - but that won't hurt too much at first.
I'll post a link to the project later.
MK
Dropbox Link:
https://www.dropbox.com/sh/u9vejrf0vm2fn1x/AAAaACwr017fXwtWkPWe9oC2a?dl=0
I won't leave it up for long, so please let me know when you download it.
It's a complete Keil MDK project, with a lot of stuff that you don't need and which will make little sense.
Concentrate on the dmx files.
I see that in this project I use the ST lib functions to set up the timer (wouldn't do that now) and I use the ST touch support library (which I had a few problems with).
You can run it in the Keil toolset (free sub 32k version) which is a big but zero cost download from www.keil.com
You will need to install the legacy support stuff as well (search legacy support on Keil website)
MK
I have downloaded it, I will finish my version without the st library before reading your code.
Thank you.
P.Congre
Good luck !
MK
Hello Michael,
Just one question, where do you define the DMX_TX_EN and DMX_TX variables in the DMX.c file?
best regard.
In xxx_project.h,
#ifndef __C459_PROJECT_H #define __C459_PROJECT_H // INCLUDES #include "stm32f0xx.h" #include <stdio.h> #include <stdbool.h> #include <stdint.h> // DEFINES #define VERSION 100 #define VERSION_STR "1.0.0" #define FALSE (false) #define TRUE (true) #define MAX_GCI_SKIPS 10 #define FLASH_SIZE 0x200000 #define SECTOR_SIZE 0x10000 #define FLASH_SECTORS 32 #define CONTEXT_SECTOR 0 #define CONTEXT_BLOCK_SIZE 1024 #define SERIALISE_VERSION 0 // must never be 0xff because also used to loactae written areas of flash //#define SET_DMX_TX_EN {GPIOA->BSRR = DMX_TX_EN;} //#define CLR_DMX_TX_EN {GPIOA->BSRR = (DMX_TX_EN) << 16;} //#define SET_FLASH_NSS {GPIOB->BSRR = FLASH_NSS;} //#define CLR_FLASH_NSS {GPIOB->BSRR = (FLASH_NSS) << 16;} //#define SET_FLASH_WP {GPIOB->BSRR = FLASH_WP;} //#define CLR_FLASH_WP {GPIOB->BSRR = (FLASH_WP) << 16;} //#define SET_PROX_STX {GPIOC->BSRR = PROX_STX;} //#define CLR_PROX_STX {GPIOC->BSRR = (PROX_STX) << 16;} //#define SET_PROX_MD {GPIOC->BSRR = PROX_MD;} //#define CLR_PROX_MD {GPIOC->BSRR = (PROX_MD) << 16;} //#define SET_PROX_SC {GPIOC->BSRR = PROX_SC;} //#define CLR_PROX_SC {GPIOC->BSRR = (PROX_SC) << 16;} // PORTA #define IR_RX 1 << 8 #define DMX_TX 1 << 9 #define DMX_RX 1 << 10 #define DMX_TX_EN 1 << 11 #define LED_9 1 << 12 #define UART2_RX 1 << 15 // PORTB #define FLASH_SCK 1 << 3 #define FLASH_MISO 1 << 4 #define FLASH_MOSI 1 << 5 #define FLASH_NSS 1 << 6 #define FLASH_WP 1 << 7 #define LED_8 1 << 15 // PORTC #define LED_2 1 << 0 #define LED_3 1 << 1 #define LED_4 1 << 2 #define LED_5 1 << 3 #define PROX_PRX 1 << 6 #define PROX_STX 1 << 7 #define PROX_MD 1 << 8 #define PROX_SC 1 << 9 #define LED_12 1 << 10 #define LED_13 1 << 11 // PORTF #define LED_6 1 << 4 #define LED_7 1 << 5 #define LED_10 1 << 6 #define LED_11 1 << 7 #define ASC_LF 0x0a #define ASC_CR 0x0d #endif
Hope this helps.
MK
In xxx_project.h,
#ifndef __C459_PROJECT_H #define __C459_PROJECT_H // INCLUDES #include "stm32f0xx.h" #include <stdio.h> #include <stdbool.h> #include <stdint.h> // DEFINES #define VERSION 100 #define VERSION_STR "1.0.0" #define FALSE (false) #define TRUE (true) #define MAX_GCI_SKIPS 10 #define FLASH_SIZE 0x200000 #define SECTOR_SIZE 0x10000 #define FLASH_SECTORS 32 #define CONTEXT_SECTOR 0 #define CONTEXT_BLOCK_SIZE 1024 #define SERIALISE_VERSION 0 // must never be 0xff because also used to loactae written areas of flash //#define SET_DMX_TX_EN {GPIOA->BSRR = DMX_TX_EN;} //#define CLR_DMX_TX_EN {GPIOA->BSRR = (DMX_TX_EN) << 16;} //#define SET_FLASH_NSS {GPIOB->BSRR = FLASH_NSS;} //#define CLR_FLASH_NSS {GPIOB->BSRR = (FLASH_NSS) << 16;} //#define SET_FLASH_WP {GPIOB->BSRR = FLASH_WP;} //#define CLR_FLASH_WP {GPIOB->BSRR = (FLASH_WP) << 16;} //#define SET_PROX_STX {GPIOC->BSRR = PROX_STX;} //#define CLR_PROX_STX {GPIOC->BSRR = (PROX_STX) << 16;} //#define SET_PROX_MD {GPIOC->BSRR = PROX_MD;} //#define CLR_PROX_MD {GPIOC->BSRR = (PROX_MD) << 16;} //#define SET_PROX_SC {GPIOC->BSRR = PROX_SC;} //#define CLR_PROX_SC {GPIOC->BSRR = (PROX_SC) << 16;} // PORTA #define IR_RX 1 << 8 #define DMX_TX 1 << 9 #define DMX_RX 1 << 10 #define DMX_TX_EN 1 << 11 #define LED_9 1 << 12 #define UART2_RX 1 << 15 // PORTB #define FLASH_SCK 1 << 3 #define FLASH_MISO 1 << 4 #define FLASH_MOSI 1 << 5 #define FLASH_NSS 1 << 6 #define FLASH_WP 1 << 7 #define LED_8 1 << 15 // PORTC #define LED_2 1 << 0 #define LED_3 1 << 1 #define LED_4 1 << 2 #define LED_5 1 << 3 #define PROX_PRX 1 << 6 #define PROX_STX 1 << 7 #define PROX_MD 1 << 8 #define PROX_SC 1 << 9 #define LED_12 1 << 10 #define LED_13 1 << 11 // PORTF #define LED_6 1 << 4 #define LED_7 1 << 5 #define LED_10 1 << 6 #define LED_11 1 << 7 #define ASC_LF 0x0a #define ASC_CR 0x0d #endif
Hope this helps.
MK