platformio / platform-ststm8

ST STM8: development platform for PlatformIO
https://registry.platformio.org/platforms/platformio/ststm8
Apache License 2.0
40 stars 26 forks source link

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

Open kokospalme opened 2 months ago

kokospalme commented 2 months ago

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
        }
    }
  }
}