Author Topic: ST Micro HAL with I2C buffer  (Read 13669 times)

0 Members and 1 Guest are viewing this topic.

Offline Gibson486Topic starter

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: us
ST Micro HAL with I2C buffer
« on: March 01, 2017, 09:09:45 pm »
I am using a STM32F4 micro with the HAL library.

For I2C (interrupt version), it seems like you need to have fixed buffer length for the slave to receive info. I am trying to figure out how I can figure out how to tell if something is in the I2C buffer. Unfortunately, the HAL is not very transparent, so I am having a tough time getting this info. I am simply looking to see the buffer size and iterate through it, but I am not sure how to determine the buffer size from the HAL. Any idea?
 

Offline thm_w

  • Super Contributor
  • ***
  • Posts: 6364
  • Country: ca
  • Non-expert
Re: ST Micro HAL with I2C buffer
« Reply #1 on: March 02, 2017, 12:22:07 am »
Do you have a set message length or can it change?
If its fixed set the buffer length to that length, then you shouldn't need to tell if something is in the buffer, just when its completely received.
If it can vary you might need to set it to length 1 (at least that is the case for usart, unsure if i2c works the same way). Then implement your own buffer to monitor.

Have you looked at the examples in: STM32Cube_FW_L4_V1.6.0\Projects\STM32L432KC-Nucleo\Examples\I2C\I2C_TwoBoards_ComIT\ (change to the F4 equivalent)?
Possibly relevant: https://community.st.com/thread/34551-about-i2c-bus
Profile -> Modify profile -> Look and Layout ->  Don't show users' signatures
 

Offline Gibson486Topic starter

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: us
Re: ST Micro HAL with I2C buffer
« Reply #2 on: March 02, 2017, 01:34:15 am »
I need it to be variable in size.

Yeah, I saw the demo code. The issue is that the buffer size is predefined as RXBUFFERSIZE....but it is defined somewhere else. To make matters worse, the function call back just toggles a LED. Not what I was expecting. I was expecting to see a nice loop that iterates through an array. The only part of the code that does that is the buffer compare function, but I am still not sure how they filled their buffers in the first place.
 

Offline capt bullshot

  • Super Contributor
  • ***
  • Posts: 3033
  • Country: de
    • Mostly useless stuff, but nice to have: wunderkis.de
Re: ST Micro HAL with I2C buffer
« Reply #3 on: March 02, 2017, 07:45:25 am »
There's one thing to tell first place when it comes to STM32 / Cube / HAL:
Don't use the provided device drivers. They appear to be coded on a very high level of cross-device abstaction level, leading to a large amount of bloat and inefficiency. They try to cover some use cases, if you have other requirements than what they provide (which isn't uncommon in world of embedded programming), IMHO it's easier to code your own driver.

There's one thing to tell first place when it comes to STM32 I2C:
Check which version if the I2C your chip has. The older one (inside the STM32F1 devices) has (too) many bugs.
Safety devices hinder evolution
 

Offline Gibson486Topic starter

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: us
Re: ST Micro HAL with I2C buffer
« Reply #4 on: March 02, 2017, 12:57:44 pm »
There's one thing to tell first place when it comes to STM32 / Cube / HAL:
Don't use the provided device drivers. They appear to be coded on a very high level of cross-device abstaction level, leading to a large amount of bloat and inefficiency. They try to cover some use cases, if you have other requirements than what they provide (which isn't uncommon in world of embedded programming), IMHO it's easier to code your own driver.

There's one thing to tell first place when it comes to STM32 I2C:
Check which version if the I2C your chip has. The older one (inside the STM32F1 devices) has (too) many bugs.


Thanks...

I noticed.

I am starting to think that I made a mistake in picking ST Micro. Everyone was telling me to use it over Freescale. It seems like everything that ST gives you is buggy as hell as well.
 

Offline capt bullshot

  • Super Contributor
  • ***
  • Posts: 3033
  • Country: de
    • Mostly useless stuff, but nice to have: wunderkis.de
Re: ST Micro HAL with I2C buffer
« Reply #5 on: March 02, 2017, 03:31:53 pm »
I am starting to think that I made a mistake in picking ST Micro. Everyone was telling me to use it over Freescale. It seems like everything that ST gives you is buggy as hell as well.

No, it ain't that bad. They all build bugs into their stuff. At least they have big marketing, and you can get many of these discovers / nucleo boards for free (if you ask the right people) or little money (from mouser etc.)
Regarding boards and tools, they made real big progress compared to the first STM32F1 (there wasn't even a useable low cost debugger). There's quite large amount of people in this world tinkering at all imaginable levels of skill with STM32F series, so you'll find a lot of support on the net. Just don't rely on their tools only (I'm also one of these "tinkerers": http://wunderkis.de/thestm32files.html )
Safety devices hinder evolution
 

Offline mark03

  • Frequent Contributor
  • **
  • Posts: 711
  • Country: us
Re: ST Micro HAL with I2C buffer
« Reply #6 on: March 02, 2017, 05:02:33 pm »
I am starting to think that I made a mistake in picking ST Micro. Everyone was telling me to use it over Freescale. It seems like everything that ST gives you is buggy as hell as well.
The ST-provided software is improving; they are making a real effort with the "Cube" stuff.  IMO it's still fairly awful, due both to poor-quality work and misguided goals.  Even so it can be handy if you need a prototype in a hurry and don't plan to carry the code forward where you'll have to maintain it.

If you just code directly from the Reference Manual, STM32 is actually quite good.  The writing (clarity and conciseness) is poor, but still better than most of their competitors, and everything you need to be successful is there.
 

Offline Gibson486Topic starter

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: us
 

Offline racemaniac

  • Contributor
  • Posts: 25
  • Country: be
Re: ST Micro HAL with I2C buffer
« Reply #8 on: March 02, 2017, 07:11:08 pm »
When you say reference manual, do you mean this?

http://www.st.com/content/ccc/resource/technical/document/user_manual/2f/71/ba/b8/75/54/47/cf/DM00105879.pdf/files/DM00105879.pdf/jcr:content/translations/en.DM00105879.pdf
Nope, if it's the reference manual, it really has "reference manual" as title on top :)
for example for the stm32f411: http://www.st.com/content/ccc/resource/technical/document/reference_manual/9b/53/39/1c/f7/01/4a/79/DM00119316.pdf/files/DM00119316.pdf/jcr:content/translations/en.DM00119316.pdf

And concerning if stm32 is a good choice. They all have there good and bad sides i guess. I started with arduino & ended up developing on STM32. I recently also started with cubemx (after first coding my own spi & i2c drivers from scratch for it.). And it's indeed far from perfect, but it does give you a decent basis to start from. You can quickly do some tests on the peripherals you want to use, and gradually replace the HAL code to your own. At first you can still use the HAL code to initialize the peripheral. Once everything is initialized, creating your own driver to use it is not too hard if you read the reference manual on how it works :).
Haven't got much experience with other mcu's yet, but i'm like stm32 so far, affordable, powerful, and well enough documented (and with a code generator that can get you started). good enough for me for now :)
 

Offline thm_w

  • Super Contributor
  • ***
  • Posts: 6364
  • Country: ca
  • Non-expert
Re: ST Micro HAL with I2C buffer
« Reply #9 on: March 03, 2017, 12:09:14 am »
Yeah, I saw the demo code. The issue is that the buffer size is predefined as RXBUFFERSIZE....but it is defined somewhere else. To make matters worse, the function call back just toggles a LED. Not what I was expecting. I was expecting to see a nice loop that iterates through an array. The only part of the code that does that is the buffer compare function, but I am still not sure how they filled their buffers in the first place.

Try a length of one and make your own buffering function.
They filled the buffer by receiving number of bytes defined by RXBUFFERSIZE (in hal_i2c.c maybe the interrupt is function I2C_ITListenCplt?). Its a shortcoming of the HAL but also makes it simpler to use in basic cases.

Code: [Select]
if(HAL_I2C_Slave_Receive_IT(&I2cHandle, (uint8_t *)aRxBuffer, 1) != HAL_OK)
In hal_i2c.c:
Code: [Select]
(+) Receive in slave mode an amount of data in non-blocking mode using HAL_I2C_Slave_Receive_IT()
(+) At reception end of transfer, HAL_I2C_SlaveRxCpltCallback() is executed and user can
           add his own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback()

So you could use the callback to fill a buffer maybe:
Code: [Select]
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *I2cHandle)
{
static int i = 0;
buffer = *I2cHandle.pBuffPtr;
if(i++ > max_length)
 i = 0;
}
Profile -> Modify profile -> Look and Layout ->  Don't show users' signatures
 

Offline Gibson486Topic starter

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: us
Re: ST Micro HAL with I2C buffer
« Reply #10 on: March 03, 2017, 09:40:35 pm »
Are you saying that RXBUFFERSIZE is not something you send, but it is determined by the actual mount of info in the buffer? I was thinking about making the buffer 1 byte, but I was unsure how it was determined. I thought RXBUFFERSIZE was something you had to define.
 

Offline thm_w

  • Super Contributor
  • ***
  • Posts: 6364
  • Country: ca
  • Non-expert
Re: ST Micro HAL with I2C buffer
« Reply #11 on: March 03, 2017, 10:20:21 pm »
Are you saying that RXBUFFERSIZE is not something you send, but it is determined by the actual mount of info in the buffer? I was thinking about making the buffer 1 byte, but I was unsure how it was determined. I thought RXBUFFERSIZE was something you had to define.

RXBUFFERSIZE is something you define yes, in their example they define it as ~147 because they know how much will be received:

Code: [Select]
uint8_t aRxBuffer[RXBUFFERSIZE];
#define RXBUFFERSIZE                      TXBUFFERSIZE
#define TXBUFFERSIZE                      (COUNTOF(aTxBuffer) - 1)
uint8_t aTxBuffer[] = " ****I2C_TwoBoards communication based on IT****  ****I2C_TwoBoards communication based on IT****  ****I2C_TwoBoards communication based on IT**** ";

If you don't know how much you are receiving, AFAIK it should be possible to set it as 1, so you can figure out what message it is and how many bytes it is.
Profile -> Modify profile -> Look and Layout ->  Don't show users' signatures
 

Offline Gibson486Topic starter

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: us
Re: ST Micro HAL with I2C buffer
« Reply #12 on: March 06, 2017, 09:06:42 pm »
Let me ask this. If we read 8 bits at a time (turn the buffer size into 1), does reading a byte clear out the byte you just read? If so, I imagine there is a register that tells me when the I2C buffer is empty.
 

Offline thm_w

  • Super Contributor
  • ***
  • Posts: 6364
  • Country: ca
  • Non-expert
Re: ST Micro HAL with I2C buffer
« Reply #13 on: March 06, 2017, 10:47:07 pm »
Let me ask this. If we read 8 bits at a time (turn the buffer size into 1), does reading a byte clear out the byte you just read? If so, I imagine there is a register that tells me when the I2C buffer is empty.

If we are talking about the high level software, reading does nothing. If you start a new HAL receipt of a byte then it will probably "clear" the previous byte. This is why you copy it to your own buffer.

At the low level there is a single byte data buffer (I2C_DR::DR pg 488)
Quote
Receiver mode: Received byte is copied into DR (RxNE=1). A continuous transmit stream
can be maintained if DR is read before the next data byte is received (RxNE=1).

If you had more than one byte come in without reading the register, you will get an overrun flag, and the new data will be lost.
So either you read that byte manually upon interrupt, get HAL to do it, or get DMA to dump it somewhere. End result is you are always doing "something" after every byte is received.
Profile -> Modify profile -> Look and Layout ->  Don't show users' signatures
 

Offline Gibson486Topic starter

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: us
Re: ST Micro HAL with I2C buffer
« Reply #14 on: March 07, 2017, 05:45:26 pm »
So, does HAL_I2C_Slave_Receive_IT() need to be called for every byte? I am a little confused because if you set the buffer size to one, wouldn't it just transfer one byte? Also, if this in an interrupt, why do we need to call HAL_I2C_Slave_Receive_IT() in the main loop?  Don't we go directly to the function call back?
 

Offline thm_w

  • Super Contributor
  • ***
  • Posts: 6364
  • Country: ca
  • Non-expert
Re: ST Micro HAL with I2C buffer
« Reply #15 on: March 07, 2017, 09:54:01 pm »
So, does HAL_I2C_Slave_Receive_IT() need to be called for every byte? I am a little confused because if you set the buffer size to one, wouldn't it just transfer one byte? Also, if this in an interrupt, why do we need to call HAL_I2C_Slave_Receive_IT() in the main loop?  Don't we go directly to the function call back?

You would have to call it for every byte, yes, because you don't know the length of the i2c packet. Once you receive the one byte, then you decide if you need to receive more or not.
May also be possible to call it once set to the length of your shortest length packet, and then receive more if needed.

HAL_I2C_Slave_Receive_IT() is called to:
- Check i2c peripheral has been setup
- Set up HAL internal locks and mode tracking, etc.
- Enable i2c interrupt

There is a lot of housekeeping its doing. Sure some of that stuff is not useful to you, but thats the cost of ease of use.
If that doesn't work for you, then you will need to write your own interrupt functions to handle incoming data.
« Last Edit: March 07, 2017, 10:04:58 pm by thm_w »
Profile -> Modify profile -> Look and Layout ->  Don't show users' signatures
 

Offline Gibson486Topic starter

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: us
Re: ST Micro HAL with I2C buffer
« Reply #16 on: March 09, 2017, 07:53:32 pm »
I think I may need to write my own driver. I tried doing it with one byte, but the problem is that it hangs. I suspect the clock is being pulled low after the first byte. The issue, as I dug further, is that the HAL for the interrupt receive only allows access to what you request in the function. Beyond on that, it seems that there is no way to have it cycle through multiple bytes by accessing the DR register. Correct me if I am wrong....
 

Offline WillHuang

  • Contributor
  • Posts: 47
Re: ST Micro HAL with I2C buffer
« Reply #17 on: March 13, 2017, 12:21:22 am »
If it helps, here's a small I2C driver I wrote for the STM32F303. It uses CMSIS:

Code: [Select]
/*!
********************************************************************************
*   \brief      Initializes the I2C1 module
*               100 KHz Mode, 140ns rise time, 40ns fall time
*               PB6 - SCL (AF4)
*               PB7 - SDA (AF4)
*   \param      'interrupt' ENABLE OR DISABLE interrupt   
*   \returns    none
********************************************************************************
*/
void I2C1_Init(void)
{
    if(!IsInit)
    {
        GPIOBClock(1);  // Enable GPIOB Clock
   
        GPIOB->MODER    &= ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7);    // Reset PB6 and PB7 Mode type
        GPIOB->MODER    |= GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1;   // Set PB6 and PB7 to AF mode
        GPIOB->OTYPER   |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7;         // Set output type to be open drain
        GPIOB->OSPEEDR  |= GPIO_OSPEEDER_OSPEEDR6 | GPIO_OSPEEDER_OSPEEDR7; // Output speed to be the highest
        GPIOB->PUPDR    &= ~(GPIO_PUPDR_PUPDR6 | GPIO_PUPDR_PUPDR7);    // No pull-up/pull-down
        GPIOB->AFR[0]   &= ~(GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7);        // Reset AF selection on PB6 and PB7
        GPIOB->AFR[0]   |= (4U << 24) | (4U << 28);                     // AF4 (I2C1) for PB6 and PB7
       
        RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // Enable I2C1 Clock
        I2C1->CR1 &= ~I2C_CR1_PE;           // Clear PE Bit
        I2C1->TIMINGR = 0x00301D2B;         // Timing for 100 kHz, 140 ns rise time, 40 ns fall time
        I2C1->CR1 |= I2C_CR1_PE;            // Enable I2C by setting PE bit in I2C_CR1 register
       
        IsInit = 1;
    }
   
}

/*!
********************************************************************************
*   \brief      Initiates a master communication
*   \param      'sAddress'  8-bit address of the slave device
*   \param      'rd_wrn'        READS from or WRITE to the slave device
*   \param      'numBytes'      The number of bytes to read or write
*   \returns    none
********************************************************************************
*/
void I2C1_BeginTransmission(uint8_t sAddress, uint8_t rd_wrn, uint8_t nBytes)
{
    while(I2C1->ISR & I2C_ISR_BUSY);    // Wait until line is not busy   
    I2C1->CR2 = 0x00;                   // Reset settings
    I2C1->CR2 = (sAddress << 1);    // Set slave address
    I2C1->CR2 |= (nBytes << 16);      // 2 Byte to be transmitted
   
   
    if(rd_wrn == 0) // Write request
    {
        I2C1->CR2 &= ~I2C_CR2_RD_WRN;
    }
    else    // Read request
    {
        I2C1->CR2 |= I2C_CR2_RD_WRN;
    }
   
   
    I2C1->CR2 |= I2C_CR2_START;         // Set START bit
   
}

/*!
********************************************************************************
*   \brief      Ends I2C communication
*   \param      none
*   \returns    none
********************************************************************************
*/
void I2C1_EndTransmission(void)
{
    while(!(I2C1->ISR & I2C_ISR_TC));   // Wait for transfer to be completed
    I2C1->CR2 |= I2C_CR2_STOP;
    I2C1->ICR |= I2C_ICR_STOPCF;        // Clear stop detection flag
}

/*!
********************************************************************************
*   \brief      Writes a single byte to a slave with a 7-bit addressing mode
*   \param      'data'  Data to write to the bus
*   \returns    none
********************************************************************************
*/
void I2C1_Write(uint8_t data)
{
   
    while(!(I2C1->ISR & I2C_ISR_TXIS));  // Wait until TXDR is empty
    I2C1->TXDR = data;                  // 8-bit data to be transmitted
   
}

/*!
********************************************************************************
*   \brief      Determines if the I2C bus is busy or not
*   \param      none
*   \returns    returns (1) if BUSY or (0) if not BUSY
********************************************************************************
*/
uint8_t I2C1_IsBusy(void)
{
    static uint8_t status;
   
    if(I2C1->ISR & I2C_ISR_BUSY) { status = 1; }
    else { status = 0; }
       
    return status;
}

 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: ST Micro HAL with I2C buffer
« Reply #18 on: March 13, 2017, 01:59:46 am »
On NXP devices, you ALWAYS implement I2C as an interrupt driven state machine.  if you are implementing a slave, the end of the message occurs when the I2C gadget interrupts with a STOP condition.  Every conceivable interrupting condition returns a unique status byte.  There is a giant case statement that is used to branch to the proper event handler.  The same state machine also handles the situation of being a master.

Given that a STOP condition is detected, you should know when the entire packet has been received.

I know absolutely nothing about the STM32 board except to say that HAL and Cube are not impressing me (I have several boards).  At some point, I would cut my losses and write my own drivers.

I2C is probably the most difficult protocol to implement.  I almost always prefer SPI and will buy the appropriate peripheral devices such that I avoid I2C whenever possible.
 

Offline Gibson486Topic starter

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: us
Re: ST Micro HAL with I2C buffer
« Reply #19 on: March 13, 2017, 04:37:49 pm »
That sounds very useful. That is what we are trying to do now. Unfortunately, at least from what I have seen, everything just goes to a generic handler routine and that is it.
 

Offline Gibson486Topic starter

  • Frequent Contributor
  • **
  • Posts: 324
  • Country: us
Re: ST Micro HAL with I2C buffer
« Reply #20 on: March 14, 2017, 08:56:41 pm »
Got it working.

I edited the handler to mimic blocking based on the state of registers. After I got it working, I just realized it was basically the blocking code (the non IT HAL code) with two more register checks. Took us a while, but the I2C protocol has never seemed more clear!

Thanks!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf