2020-12-13 03:27 PM
Hi everyone,
I am trying to output DMX data over UART1 at 25Hz. Therefore I need a break for 88us. My plan was to take control over the port and set it into GPIO Mode. After 88us I set it back to UART mode.
For breaktimes > 250us it works fine. But below that value the voltage spike only goes to roundabout 800mV. What am I doing wrong?
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim == &htim3) {
setGPIOMode();
// wait 88 microseconds for the DMX break
delay_us(88);
setUartMode();
// wait 8 microseconds for the MAB (Mark After Break)
delay_us(8);
}
}
void setGPIOMode() {
GPIOA->MODER = (GPIOA->MODER & ~GPIO_MODER_MODER9_Msk) | (1 << GPIO_MODER_MODER9_Pos);
}
void setUartMode() {
GPIOA->MODER = (GPIOA->MODER & ~GPIO_MODER_MODER9_Msk) | (2 << GPIO_MODER_MODER9_Pos);
}
void delay_us (uint16_t us)
{
__HAL_TIM_SET_COUNTER(&htim2,0); // set the counter value a 0
while (__HAL_TIM_GET_COUNTER(&htim2) < us); // wait for the counter to reach the us input in the parameter
}
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;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
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};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 83;
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();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
/**
* @brief TIM3 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM3_Init(void)
{
/* USER CODE BEGIN TIM3_Init 0 */
/* USER CODE END TIM3_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM3_Init 1 */
/* USER CODE END TIM3_Init 1 */
htim3.Instance = TIM3;
htim3.Init.Prescaler = 55;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 59999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM3_Init 2 */
/* USER CODE END TIM3_Init 2 */
}
2020-12-13 04:05 PM
Where and how do you measure that voltage? Can you show oscilloscope screenshots for the two different cases?
JW
2020-12-14 12:12 AM
Hey Jan,
sure! Here are pictures with the delay set to 80us / 3000us.
2020-12-14 02:11 AM
Can't this be just your oscilloscope's limitation?
Do you measure after some optocoupler? If yes, try measuring directly on mcu pin.
JW
2020-12-15 12:49 PM
Hey Jan,
I also had this thought. But toggling a normal GPIO pin with 80us delay in between works fine and the oscilloscope (100MHz 1GSa/s) displays the correct voltage (around 3,3V). I am measuring directly on the pin.
//I tried this code and the voltage of PD9 is at arround 300mV, the voltage of the oszi_Pin is at 3,3V
HAL_GPIO_TogglePin(oszi_GPIO_Port, oszi_Pin);
setGPIOMode();
delay_us(88);
setUartMode();
HAL_GPIO_TogglePin(oszi_GPIO_Port, oszi_Pin);
delay_us(88);
2020-12-15 03:25 PM
Tx on PA9 at 250kBaud works normally? at 250kBaud, one bit is 4us, if you transmit something like 0x55, do you see individual bits?
How is GPIO_OSPEEDR set for PA9? GPIO_ODR is set to 0 for PA9, I presume; but maybe you should read out the GPIOA registers and post them here.
Do you use OTG_FS?
JW
2020-12-16 05:33 AM
Hey Jan,
I should have probably mentioned that I'm using a STM32F407 discovery board. I found out that UART2 works fine for my purposes. I think that there must be any components on the board which disturb USART1. Could that be possible?
2020-12-16 06:43 AM
Hey Jan,
thank you for your help. I can now successfully output DMX.
Edit for others with probably the same problem:
I figured out that there is a problem on the STM32F407 Discovery board when trying to use UART1. Using another UART solved the problem for me. I think there are some components on the PCB which cause problems with higher baud rates on UART1.
I have another question (I don't know if I should open another thread for that). I now have one DMX output. My goal is to output way more data (8 DMX ports). Where should I begin researching this "multi" task? Just outputting the universes one after one should be too slow in my thought.
Is FreeRTOS the way to go for?
2020-12-17 10:33 PM
@PUrsu.1 Would you consider using the PWM to generate the DMX512 signal ? there seems to be a lot of timers on the STM32F407 which can be used for PWM outputs