Electrical – STM32: Manchester coding bit banging implementation problem

bit-bangmanchester-codingserialstm32stm32f4

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!

Best Answer

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.