0
\$\begingroup\$

I want to use Manchester Coding for my DALI Master-slave project. I am using two boards for this project, one is STM32E407 and the other is STM32F3Discovery. As an initial step, I want to test for sending simple hex data(0xFE96)[FE-Preamble data, 96 is the command I want to send] from STM32F3Discovery to STM32E407 using Manchester coding following this App_Note, with time-based decoding approach. I have configured both boards for the same clock configuration.

Programming: Manch_Tx (Encoding) part was very easy and working quite as expected. The problem for me is with Manch_Rx(Decoding) part. I have configured TIMer4(CH3) of STM32E407, for a period of 0xFFFF and up-count mode.According to my clock configuration, timer peripheral clock frequency is 64MHz. I have configured one external interrupt pin triggered by user_button on STM32F3Discovery for hardware flow control.

Various aspects that I have considered:

  1. I have made sure the data transfer will start with external interrupt(push_button on STM32F3-Discovery) which triggers input capture on STM32E407.
  2. I have even experimented to include some delay(few msecs) for the data transfer to start.
  3. Tweaking with NVIC priority for timer (Not exactly know any standard method, was just giving less priority to Timer as Systick)
  4. Using pulse_frequency rather than pulse_width(time) to avoid float

I am using HAL_TIM_IC_CaptureCallback() function to measure the pulse frequency as follows.

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
   {
   if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_3)
   {

     if(uhCaptureIndex == 0)
     {
       /* Get the 1st Input Capture value */
       uwIC3Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
       uhCaptureIndex = 1;
     }
     else if(uhCaptureIndex == 1)
     {
        /* Get the 2nd Input Capture value */
        uwIC3Value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
       /* Capture comuputation */
       if (uwIC3Value2 > uwIC3Value1)
       {
         uwDiffCapture = (uwIC3Value2 - uwIC3Value1);
       }
       else /* (uwIC3Value2 <= uwIC3Value1) */
       {
         uwDiffCapture = ((0xFFFF - uwIC3Value1) + uwIC3Value2);
       }
       /* Calculation of 'window_T' */
       /* pulse_T = uwDiffCapture / (2*HAL_RCC_GetPCLK1Freq()); */
       /* Calcualtion of pulse_Frequency */
       pulse_Frequency = (2*HAL_RCC_GetPCLK1Freq()) / uwDiffCapture;
       uhCaptureIndex = 0;
     }
  }

}

Main function

  int main(void)
  {
    HAL_Init();
    /* Configure the system clock */
    SystemClock_Config();
    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_TIM4_Init();

    while(interrupt_detected == 0)
    {
    }
   if(HAL_TIM_IC_Start_IT(&htim4, TIM_CHANNEL_3) != HAL_OK)
    {
     _Error_Handler(__FILE__, __LINE__);
    }

    /* Test in general the value of uwDiffCapture */
    /* while(!(pulse_Frequency > (2*Freq_T-Freq_Delta_T) && (pulse_Frequency < (2*Freq_T+Freq_Delta_T)))) */
    /*   { */
    /*     HAL_TIM_IC_CaptureCallback(&htim4); */
    /*     HAL_GPIO_TogglePin(LED_Red_GPIO_Port, LED_Red_Pin); */
    /*     HAL_Delay(250); */
    /*   } */
    while(!((pulse_Frequency > 4000) && (pulse_Frequency < 10000)))
    {
      HAL_TIM_IC_CaptureCallback(&htim4);
      HAL_GPIO_TogglePin(LED_Red_GPIO_Port, LED_Red_Pin);
      HAL_Delay(250);
    }
    HAL_GPIO_WritePin(LED_Red_GPIO_Port, LED_Red_Pin, GPIO_PIN_RESET);

    /* When it is in sync turn on LED_Green */
    HAL_GPIO_WritePin(LED_Green_GPIO_Port, LED_Green_Pin, GPIO_PIN_SET);
    while (1)
    {
    }
  }

My Understanding:

   Min_pulse_frequency = 2*TIM4_Peripheral_Frequency/Period 

I was using T(mid_bit_time) as 125usec[corresponding pulse_frequency 8kHz] for Manch_Tx func(). I want to make sure that on receiving side pulse_frequency lies between 2*T-Delta_T and 2*T+Delta_T as a first debugging step [before the complete implementation of Manch_Rx func()] and this is where I am having the problem. I am converting time data into frequency and comparing that the pulse_frequency lies within limits. The wrote 4000, 10000 values are calculated based on expected frequency and adding some heavy tolerance. I am not getting any reliable results.

My questions are:

  1. What am I missing or where is my understanding wrong?
  2. In general, my logic of calling HAL_TIM_IC_CaptureCallback[non-blocking mode] correct or should I have to use TIM4_IRQHandler()[blocking-mode] ??
  3. Is the entire process less painful if I use DMA for time capture?

PS: I am using HAL_Libraries as you can see and (openocd, linux, Emacs and jtag ) interface.

EDIT: The problem lies in using HAL_TIM_IC_CaptureCallback() function. In the HAL library, HAL_TIM_IC_CaptureCallback() is only used to report for update of events in Capture or Compare mode that is the reason why calling CaptureCallback does not work to measure the signal period. Instead, I have to use IRQHandler and this is what makes it more complicated!

\$\endgroup\$
7
  • \$\begingroup\$ Simple Bi-phase decoders use 3T/4 one shot to sync clock and decode data. \$\endgroup\$
    – D.A.S.
    Commented Nov 28, 2017 at 23:19
  • 1
    \$\begingroup\$ Better ones use the clock edge only with the 3/4T one shot with a PLL to reduce clock jitter then integrate the data over each half bit interval and take the difference. But you can simply use the non-retriggerable one shot to trigger on same edge (+ or -) as clock so that it becomes the simple clock recovery , then the data can be sampled by the phase or analog level at 1/4T or 3/4T for the bit value as long as jitter < 10% In hardware it is just and XOR gate , to transmit and 1shot and FF to Rx. \$\endgroup\$
    – D.A.S.
    Commented Nov 29, 2017 at 1:00
  • 1
    \$\begingroup\$ @TonyStewart.EEsince'75 Unfortunately DALI isn't a well behaved Manchester signal in the way you are expecting. The receiver has to accept pulses that are up to 20% off nominal and this can vary per logical bit from one end of the tolerance to the other, in fact there is a specific test for this. The lack of a preamble to train a PLL prevents simple hardware solutions, AFAIK. Therefore you have to just measure all the pulse times using edge triggers. \$\endgroup\$
    – Martin
    Commented Nov 29, 2017 at 9:19
  • \$\begingroup\$ @TonyStewart.EEsince'75 Are you suggesting me to use Biphase decoding stead Manchester? But DALI as a standard uses Manchester coding. Please clarify! I could not understand what you are suggesting. \$\endgroup\$
    – charansai
    Commented Nov 29, 2017 at 9:57
  • \$\begingroup\$ @Martin Even though now I am not looking at complications involved in Manchester implementation for DALI, could you explain which "specific test" you are talking about? and Is there any good documentation available on the transmission side of DALI? Thank you. \$\endgroup\$
    – charansai
    Commented Nov 29, 2017 at 10:00

1 Answer 1

0
\$\begingroup\$

This is how I have finally solved the problem. This should conclude my problem

void TIM4_IRQHandler(void)
{

  HAL_TIM_IRQHandler(&htim4);
  /* USER CODE BEGIN TIM4_IRQn 1 */

  if(i < 9)
   {
    /* Capture the timer value when interrupt occured */
     tmp[1] = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_3);

    if(tmp[1] > tmp[0])
     {
      uwDiffCapture = tmp[1] - tmp[0];
     }
     else /* if tmp[1] <= tmp[0]*/
       {
         uwDiffCapture = (0xFFFF - tmp[0]) + tmp[1];
       }
     /* Left shifting the vector */
     tmp[0] = tmp[1];

     if (clock_sync == 1)
     {
       if(update_variable == 0)
       {
          if ((uwDiffCapture > 6000) && (uwDiffCapture < 7000))
            {
              update_variable = 1;
              i = i-1;
            }
          else if ((uwDiffCapture > 12000) && (uwDiffCapture < 13000))
            {
             msg[i] = !Current_bit;
            }
          else 
            {
              Manch_Error();
            }

    }
  else if(update_variable == 1)
    {
      /* only execute the next block if that some variable =1; */

      /* Wait for next interupt but How ?? */
      if((uwDiffCapture > 6000) && (uwDiffCapture < 7000))
    {
      msg[i] = Current_bit;
              update_variable = 0;

    }
      else
    {

      Manch_Error();
    }

    }
  Current_bit = msg[i];
  i++;

}

  if(clock_sync == 0)
{

  if((uwDiffCapture > 12700) && (uwDiffCapture < 12900 ))
    {

      clock_sync = 1;
      if(HAL_GPIO_ReadPin(TIM_4_3_GPIO_Port, TIM_4_3_Pin) == GPIO_PIN_RESET)
    {
      Current_bit = 0;

    }
      else if(HAL_GPIO_ReadPin(TIM_4_3_GPIO_Port, TIM_4_3_Pin) == GPIO_PIN_SET)
    {
      Current_bit = 1;

    }
      else
    {

      Manch_Error();
    }

    }
  }

}
}

My trick was to write complete decoding in IRQHandler(), this way I could avoid volatile variable usage and compiler optimizations.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.