Skip to content

unstable datastream (UART with interrupts)/ DMX implementation #62

@kokospalme

Description

@kokospalme

the project: I want to dim an RGB-LED with PWM (MCU: STM8S103). The amount of dimming should be received as a datastream over DMX which is implemented via serial.
the problem: When I send data on a specific channel, the data is received, but there's a shift in the channel... So if I send data on channel 0 (DMXchannel 1), the channel which receives the data is drifting from 0 to 511, or even no data is received. So the system seem to be very unstable. Does someone know what could be the problem? here is my sktech:

/*
18.4.24, DMX sketch
DMX receiving-sketch
based on the uart loopback example: https://registry.platformio.org/platforms/platformio/ststm8/examples/spl-uart-loopback
PWM implementation based on: https://embedded-lab.com/blog/starting-stm8-microcontrollers/20/
*/

/* Includes ------------------------------------------------------------------*/
#include <Arduino.h>

/*  Defines -----------------------------------------------------------------*/
#define DMX_CHANNEL_COUNT 512 //all 512 DMX channel
#define DMX_CHANNEL_LED 1 //DMX Data on channel 1
volatile bool dmxMessageStarted = false;  //true if databytes are received 
volatile bool dataFree = false; //true if nothing is written in array by interrupt
volatile uint8_t dmxData[DMX_CHANNEL_COUNT];  //array to store DMX data in
volatile uint16_t dmxIndex = 0;

/* Private function prototypes -----------------------------------------------*/
static void CLK_Config(void);
static void UART_Config(void);
void GPIO_setup(void);
void TIM2_setup(void);

void main(void)
{
  
  pinMode(LED_BUILTIN, OUTPUT);

  CLK_Config(); //configure prescaler
  GPIO_setup();
  TIM2_setup();
  UART_Config();  //configure UART

  while(TRUE)
  {
    if(dataFree){ //if data array is not used by interrupt
      TIM2_SetCompare1(dmxData[DMX_CHANNEL_LED-1]);
      TIM2_SetCompare2(dmxData[DMX_CHANNEL_LED]);
      TIM2_SetCompare3(dmxData[DMX_CHANNEL_LED+1]);
      // TIM2_SetCompare3(128);  //Test-data on pin PA3
    }
  };
}


static void CLK_Config(void)
{
    /* Initialization of the clock */
    /* Clock divider to HSI/1 */
    CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);


    //  reset clock
    CLK_DeInit();

    // Deactivate external and internal oscillator, activate internal oscillator
    CLK_HSECmd(DISABLE);
    CLK_LSICmd(DISABLE);
    CLK_HSICmd(ENABLE);
    // Wawait until oscillator is stable
    while(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE);

    // Clock Switching
    CLK_ClockSwitchCmd(ENABLE);
    CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
    CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);

    // config for clock switching
    CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI,
    DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);

    // Deactivate clock for peripherals that are not required
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE);
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE);
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE);
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE);
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, ENABLE);
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE);
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, ENABLE);
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, DISABLE);
}

void GPIO_setup(void)
{
      GPIO_DeInit(GPIOA);
      GPIO_Init(GPIOA, GPIO_PIN_3, GPIO_MODE_OUT_PP_HIGH_FAST);

      GPIO_DeInit(GPIOD);
      GPIO_Init(GPIOD, ((GPIO_Pin_TypeDef)GPIO_PIN_3 | GPIO_PIN_4),
                GPIO_MODE_OUT_PP_HIGH_FAST);
}

// initialize timer 2 for PWM
void TIM2_setup(void)
{
      
      TIM2_DeInit();  // reset timer 2
      TIM2_TimeBaseInit(TIM2_PRESCALER_32, 255);  // Timer 2 als Zeitbasis mit Vorteiler 32 und Periodenwert 1000 initialisieren
      TIM2_OC1Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE, 255, // set timer 2 channel 1 as pwm, activate output, pulse and polarity
                   TIM2_OCPOLARITY_HIGH);

      TIM2_OC2Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE, 255,// set timer 2 channel 2 as pwm, activate output, pulse and polarity
                   TIM2_OCPOLARITY_LOW);

      TIM2_OC3Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE, 255, // set timer 2 channel 3 as pwm, activate output, pulse and polarity
                   TIM2_OCPOLARITY_HIGH);
      TIM2_Cmd(ENABLE); // activate timer 2
}

void UART_Config(void)
{
  UART1_DeInit();
  
  // Configure UART1 for DMX mode
  UART1_Init(250000, 
             UART1_WORDLENGTH_8D, 
             UART1_STOPBITS_2, // 2 Stop-Bits für DMX
             UART1_PARITY_NO,
             UART1_SYNCMODE_CLOCK_DISABLE,
             UART1_MODE_RX_ENABLE);
  
  // Enable DMX receiver interrupt
  UART1_ITConfig(UART1_IT_RXNE_OR, ENABLE);
  
  // Enable global interrupts
  enableInterrupts();
}



INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
  if (UART1_GetITStatus(UART1_IT_RXNE) != RESET)
  {
    uint8_t receivedData = UART1_ReceiveData8(); //  receive data

    if (dmxMessageStarted)
    {
      dataFree = false;
      dmxData[dmxIndex] = receivedData; // write data in array
      dmxIndex++;
      if (dmxIndex >= DMX_CHANNEL_COUNT)
      {

          dmxIndex = 0;
          dmxMessageStarted = false;
      }
    }
    else
    {
        // break signal
        if (receivedData == 0)
        {
            // digitalWrite(LED_BUILTIN, HIGH);
            dataFree = true;
            dmxMessageStarted = true; // begin of a new DMX message
            dmxIndex = 0; // reset index
        }
    }
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions