cancel
Showing results for 
Search instead for 
Did you mean: 

MDIO bit banging data rate Hello, We have implemented MDIO(Management Data Input/Output) protocol by bit banging in the STM32 Nucleo-L series board and the corresponding frequency of MDIO is 2.8MHz as of now.

sa.2
Associate

My requirement is to increase this frequency since the MCU operates at 110MHz. Kindly share your ideas ! --regards

0693W00000Y7SIcQAN.png

6 REPLIES 6
Bob S
Principal

While L series part? L0? L4? L5? And what frequency are you trying to reach? Or is it just a poorly-defined "go faster"? And why does it need to be faster? MDIO PHY access isn't usually THAT much of a time critical thing.

110MHz CPU clock and 2.8MHz bitbang clock rate means 39 CPU cycles per bitbang clock pulse. That isn't much, and that ignores any additional cycles that may be spent with FLASH wait states and/or RAM access delays through the switch fabric (including stack push/pop on function calls).

But without seeing your code there is not much we can suggest beyond generic things - higher compiler optimizations, are interrupts slowing things down, remove function calls and in-line everything, careful placement of stack and variables CCM RAM, move code from FLASH into RAM, pre-compute the bitstream and use DMA to the GPIO port.

110MHz L5 most likely

What speed do you need? Could you do efficiently with CPLD/FPGA ?

The comment was edited to adhere the community guidelines.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
VThan.2
Associate III

Hello,

Thank you for replying to my team mate's question. Here is the code for MDIO write and read. The MCU we are using is STM32L552MEY6

void OUT (unsigned long data, unsigned char p) 

{

unsigned char j;

  // Output a value to the management interface.

  data <<= (32 - p);

  for ( j=0; j<p; j++ ) 

    if (data & 0x80000000)//0x80000000=true? 1010 & 1000,0100 & 1000=0,1000 & 1000 =1,0000 

      {

      //SET_MDIO_PIN_HIGH;

      HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,1);

}

    else

      {

      //SET_MDIO_PIN_LOW;

HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,0);

      }

HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,1);   

HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,0);

     

    data <<= 1;

     

    }

void WRITE( unsigned int phy_ad, unsigned int reg_ad,unsigned int Value)// mdio write

{

OUT(0xFFFFFFFF, 32);

OUT (0x00000005, 4);

OUT ((unsigned long)phy_ad, 5);

OUT ((unsigned long)reg_ad, 5);

OUT(0x02, 2); // turnaround time 

OUT(Value, 0xFDAC);// 16 bit data

}

Just thinking about FPGA to do this more efficiently. Just trying to understand when to make that pivot? The board contains one MCU pinging 5 PHY chipsets and reporting data over serial protocol to a GUI.

Danish1
Lead II

Looking at your code, I see frequent calls to HAL_GPIO_WritePin()

Remember that's a function, for which you'll have a function-call and all the processor-overheads that it involves.

The fastest way to set a bit in a port is by writing directly to GPIOx->BSRR

To set bit 0 in GPIOB you would do

GPIOB->BSRR = 1;

And to clear that bit you would do

GPIOB->BSRR = 0x10000;

To get a better understanding of what's going on here, I strongly recommend that you read chapter on General Purpose I/Os (GPIO) in the Reference Manual for your stm32. You could also look at the source code for HAL_GPIO_WritePin(), which might be something like (here it is from stm32l4xx_hal_gpio.c)

/**
  * @brief  Set or clear the selected data port bit.
  *
  * @note   This function uses GPIOx_BSRR and GPIOx_BRR registers to allow atomic read/modify
  *         accesses. In this way, there is no risk of an IRQ occurring between
  *         the read and the modify access.
  *
  * @param  GPIOx where x can be (A..H) to select the GPIO peripheral for STM32L4 family
  * @param  GPIO_Pin specifies the port bit to be written.
  *         This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
  * @param  PinState specifies the value to be written to the selected bit.
  *         This parameter can be one of the GPIO_PinState enum values:
  *            @arg GPIO_PIN_RESET: to clear the port pin
  *            @arg GPIO_PIN_SET: to set the port pin
  * @retval None
  */
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{
  /* Check the parameters */
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  assert_param(IS_GPIO_PIN_ACTION(PinState));
 
  if(PinState != GPIO_PIN_RESET)
  {
    GPIOx->BSRR = (uint32_t)GPIO_Pin;
  }
  else
  {
    GPIOx->BRR = (uint32_t)GPIO_Pin;
  }
}

Edit: Note that BRR is simply a 16-bit access to the high 16-bits of BSRR.

Depending whether you are in Debug or Release builds, and what optimisations you selected, the asserts might be ignored altogether, but you are still wasting processor-cycles by having a function-call and an if-statement.

Regards,

Danish

gbm
Lead III

Replace the body of your loop with:

GPIOB->BSRR = data & 0x80000000 ? GPIO_PIN_4 : GPIO_PIN_4 << 16;

data <<= 1;

Hello Danish,

Thanks for your reply, yes have been into looking the reference manual of our particular board and thereby "SET" the BSRR reg and got pull down frequency from 2.6Mhz to 250 Hz. I know it should increase as you said earlier (by eliminating the function call for HAL_WRITE_PIN). Kindly share your thoughts on these anomalies!

0693W00000Y8RBiQAN.jpgCode:

while (1)

 {

 

GPIOB->BSRR = (uint32_t) GPIO_PIN_6;

GPIOB->BSRR = (uint32_t) GPIO_PIN_6 << 16U;

}

Note: Just trying to toggle the GPIO pin 6 and then if it meets our requirements can implement the same in MDIO fun calls !!

regards

Sa.2