cancel
Showing results for 
Search instead for 
Did you mean: 

directly read register status instead of HAL_GPIO_Readpin();

YTimm.1
Associate II

i am trying to bit bang 14 bits grey code. my output is not steady

uint16_t readbits(uint16_t dataPin, uint16_t clockPin) {

 uint16_t value =0;

  for (int i = 0; i <14; ++i) {

  value <<= 1;

  HAL_GPIO_WritePin(GPIOC, clockPin, GPIO_PIN_RESET);

  delay_us(20);

  HAL_GPIO_WritePin(GPIOC, clockPin, GPIO_PIN_SET);

  delay_us(20);

    value |= HAL_GPIO_ReadPin(GPIOC, dataPin);

  }

  return value;

 }

i think HAL_GPIO_ReadPin is not fast enough

in the while loop ()

DATA1 = readbits(DATA1_L_Pin, CLK_SSI_PORT_Pin);

how can change HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_2); for example to read register status?

12 REPLIES 12
Danish1
Lead II

It looks as though you are trying to bit-bang over an interface similar to SPI, where the stm32 is in control of the data clocking.

As such, making it faster will only improve things if the data are changing too rapidly for your slow read-process, but will be stable over a faster read-process.

I don't see mention of what device is generating this grey code. Telling us might help us.

I see some issues with your code.

  • The first is that you are clocking in 14 bits. 14 is unusual; I would normally expect a multiple of 8 bits, even if not all 8 bits are used.
  • Do you have a "chip select" line as well, that you pull low prior to reading the bits, then high when done? If not, how do you ensure that what the source device thinks is the first bit, is actually the first bit that your stm32 sees?
  • One other thing to check is what clock-edge does the data actually change on. If the data changes on the falling edge, your code is fine.

Hope this helps,

Danish

Ozone
Lead

> i am trying to bit bang 14 bits grey code. my output is not steady

I had done similar thing in one of my former companies, no vendor supported biphase (differential manchester code) out-of-the-box.

And of course you can hit direct on the GPIO in/out registers.

Use the appropriate GPIO struct, which is an overlay of the actual peripheral. The register names depend a bit on the derivate.

STMs also have BSR and BRR register (bit set and bit reset, or combined to BSRR), which are very useful in your case.

I would avoid using HAL delay() function, and use a timer interrupt instead.

thanks for the fast answer !, i will explain something. The result of uint16 is because i think this is the best way to save the resulting data. The data need to change on the rising edge.

the uC is the master of the clock, according to my logic analyser it is around 24KHz. SSI needs to have a time-out after the 14-bit word. it needs to change to high after it.

the sensor gives data on the falling edge. I use 4 of them so i need to make a function after to read 4 of this words with one clock but that is a problem for later, first to fix one of them.

some backgrounth: i try to read SSI absolute encoder. First MSB and last LSB in total a word of 14 bits: resolution 16384. The sensor is in grey code and no chip select option. i read on internet something like this: (this is for 25 bit encoder)

#define EncDataBit PIND2 // PD2 pin 2 of port D input

#define EncClock PORTD3 // PD3 pin 3 of port D output

int count;

uint32_t encData = 0;

uint32_t binData = 0;

encData = 0;

PORTD &= ~(1 << EncClock); // set output PD3 of PORTD low (0) Encoder Clock

_delay_us(10);

for(count = 0; count < 25; count++) {

PORTD |= (1 << EncClock); // set output PD3 of PORTD high (1) Encoder Clock

_delay_us(5);

if(bit_is_clear(PIND,EncDataBit)) {

encData = encData << 1;

} else {

encData = encData << 1;

encData = encData + 1;

}

_delay_us(5);

PORTD &= ~(1 << EncClock); // set output PD3 of PORTD low (0) Encoder Clock

_delay_us(10);

}

i know what is happening here but get a lot of errors to convert this code in STM32CubeIDE. maybe is this more information about the problem

some tips would be nice, thanks in advance

yes that is a great option. Can i generate a kind of clock with it? and yes i agree to avoid HAL_ functions, this is blocking in code>? on internet i cant find a good example for doing this.

the delay_us();

void delay_init ()

{

HAL_TIM_Base_Start(&htim10); // change this according to ur setup

}

void delay_us (uint16_t delay)

{

__HAL_TIM_SET_COUNTER(&htim10, 0); // reset the counter

while ((__HAL_TIM_GET_COUNTER(&htim10))<delay); // wait for the delay to complete

}

thanks for your reply

code what i got now:

#define SSI_CLK_BIT CLK_SSI_PORT_Pin

#define SSI_CLK_PORT CLK_SSI_PORT_GPIO_Port

#define SSI_DTA_BIT DATA1_L_Pin

#define SSI_DTA_PORT GPIOC

uint16_t DATA1_ReadSSI (void)

 {

  uint8_t bit_count_data;

  uint8_t u8portdata1;

  uint16_t data1;

  for (bit_count_data=0; bit_count_data<14; bit_count_data++)

  {

  // falling edge on clock port

  SSI_CLK_PORT &= ~(1 << SSI_CLK_BIT); lvalue needed on left hand operand of assignement

  // left-shift the current result

  data1 = (data1 << 1);

  // read the port data

  u8portdata1 = SSI_DTA_PORT; assignement makes integer from pointer whithout a cast

  // rising edge on clock port, data changes

  SSI_CLK_PORT |= (1 << SSI_CLK_BIT); lvalue needed on left hand operand of assignement

  // evaluate the port data (port set or clear)

  if ( (u8portdata1 & (1 << SSI_DTA_BIT)) != 0)

  {

  // bit is set, set LSB of result

  data1 = data1 | 0x01;

  } // if

  } // for

  return data1;

 }

I avoid Cube/HAL, and haven't used it in any of my projects.

I would setup a simple timer (up or down) with the bit time, and handle the bit set/reset stuff in the interrupt handler.

After the last bit, disable the interrupt from within the handler.

Never directly dealt with gray code.

But we used the timer for our biphase reception as well, without interrupts.

We just evaluated the timing of the phase changes (timer values), and checked if they were in limits.

This was about the DALI interface standard, that requires timing tolerance checks.

SSI_CLK_PORT &= ~(1 << SSI_CLK_BIT); lvalue needed on left hand operand of assignement

u8portdata1 = SSI_DTA_PORT; assignement makes integer from pointer whithout a cast

SSI_CLK_PORT |= (1 << SSI_CLK_BIT); lvalue needed on left hand operand of assignement

You need to dereference pointers.

This is how it looked like in my code, mostly SPL-based.

 GPIOA->BSRR = <value>;

Here an example definition of the GPIO struct type, from stm32f30x.h (SPL-based.

I believe Cube/HAL still stick to this method.

Use them, don't make up your own definitions. You are likely to introduce typos and errors.

typedef struct
{
 __IO uint32_t MODER;       /*!< GPIO port mode register,                                 Address offset: 0x00 */
 __IO uint16_t OTYPER;      /*!< GPIO port output type register,                          Address offset: 0x04 */
 uint16_t RESERVED0;        /*!< Reserved,                                                                0x06 */
 __IO uint32_t OSPEEDR;     /*!< GPIO port output speed register,                         Address offset: 0x08 */
 __IO uint32_t PUPDR;       /*!< GPIO port pull-up/pull-down register,                    Address offset: 0x0C */
 __IO uint16_t IDR;         /*!< GPIO port input data register,                           Address offset: 0x10 */
 uint16_t RESERVED1;        /*!< Reserved,                                                                0x12 */
 __IO uint16_t ODR;         /*!< GPIO port output data register,                          Address offset: 0x14 */
 uint16_t RESERVED2;        /*!< Reserved,                                                                0x16 */
 __IO uint32_t BSRR;        /*!< GPIO port bit set/reset registerBSRR,                    Address offset: 0x18 */
 __IO uint32_t LCKR;        /*!< GPIO port configuration lock register,                   Address offset: 0x1C */
 __IO uint32_t AFR[2];      /*!< GPIO alternate function low register,               Address offset: 0x20-0x24 */
 __IO uint16_t BRR;         /*!< GPIO bit reset register,                                 Address offset: 0x28 */
 uint16_t RESERVED3;        /*!< Reserved,                                                                0x2A */
}GPIO_TypeDef;
...
#define GPIOA_BASE           (AHB2PERIPH_BASE + 0x0000)
...
#define GPIOA              ((GPIO_TypeDef *) GPIOA_BASE)
 
 

TDK
Guru

Your code would look something like this instead:

for (int i = 0; i <14; ++i) {
  value <<= 1;
  // HAL_GPIO_WritePin(GPIOC, clockPin, GPIO_PIN_RESET);
  GPIOC->BSRR = clockPin << 16;
  delay_us(20);
  // HAL_GPIO_WritePin(GPIOC, clockPin, GPIO_PIN_SET);
  GPIOC->BSRR = clockPin;
  delay_us(20);
  // value |= HAL_GPIO_ReadPin(GPIOC, dataPin);
  if (GPIOC->IDR & dataPin) {
    value |= 1;
  }
}

If you feel a post has answered your question, please click "Accept as Solution".

thanks i will try !