STM32: Manchester Coding with bit banging problem

Started by charanbandi 7 months ago3 replieslatest reply 7 months ago212 views

Hello everyone,

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 = 2*64MHz/65535 ~ 1.95kHz

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 correct or should I have to use  TIM4_IRQHandler() ??

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.

[ - ]
Reply by charanbandiNovember 30, 2017

I have got it figured out! The problem lies in using HAL_TIM_IC_CaptureCallback() function. I think, it just reports the two captured values and stops capturing further and it will not report every time there is an interrupt occurring rather just reports back one capture only.

    void TIM4_IRQHandler(void)

    {

       HAL_TIM_IRQHandler(&htim4);

       /* USER CODE BEGIN TIM4_IRQn 1 */

       if(uhCaptureIndex == 0)

      {

         /* Get the 1st Input Capture value */

         uwIC3Value1 = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_3);

         uhCaptureIndex = 1;

       }

      else if(uhCaptureIndex == 1)

       {

        /* Get the 2nd Input Capture value */

        uwIC3Value2 = HAL_TIM_ReadCapturedValue(&htim4, 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;

      }

     if((uwDiffCapture > 6000) && (uwDiffCapture < 6900))

     {

       uPulseFrequency = 1;

      }

     if((uwDiffCapture > 12600) && (uwDiffCapture < 12900))

      {

       uPulseFrequency2 = 1;

      }

     }

Now in Main() function, I can just call for variables uPulseFrequency variables to change from 0 to 1 to report back the capture of T(mid_bit_time) and 2T values with appropriate tolerances.It is working fine! 


It is interesting to see that I actually have to decrease the peripheral timer clock frequency to capture low-frequency values as the max period that TIM4 can have is 0xFFFF.I know it is not a complete solution for the complete Manchester Decoding. But I can pursue it further from here. If I am successful with complete implementation, I would post the complete code here.

[ - ]
Reply by kabelltexNovember 30, 2017

I have not tried to follow your logic beyond the general notion of you sampling the received data attempting to do the decode.  Recommend you consider using edge triggered GPIO interrupts on the receiving end assuming your micro supports this feature --  most that have this allow you to change the sense of the edge (rising or falling) so the idea would be to start a timer at the rising or falling edge, change the sense of the edge trigger to the opposite edge and record the timer for the length of the negative (low) or positive (hi) pulse and reset the timer for the next pulse.  Since manchester encoding has both a low-to-high and high-to-low transition for every bit, it should be pretty easy to synch up and decode the data with the timings of the various pulses.

Regards,

Keith Abell

[ - ]
Reply by charanbandiNovember 30, 2017

Thank you for your valuable input.