2020-11-11 01:19 AM
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?
2020-11-11 01:53 AM
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.
Hope this helps,
Danish
2020-11-11 02:10 AM
> 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.
2020-11-11 02:25 AM
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
2020-11-11 02:28 AM
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
2020-11-11 03:25 AM
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;
}
2020-11-11 03:29 AM
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.
2020-11-11 04:57 AM
> 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)
2020-11-11 06:15 AM
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;
}
}
2020-11-11 07:49 AM
thanks i will try !