I2C repeated start - i2c

I am trying to use TC74 (or DS1621) temperature sensor which comes with I2C interface. My I2C ISR is able so far to write command and config bytes to the chip. However I don't know how to instruct the ISR to jump to state 0x10 (repeated start) for a read operation. The read procedure is as following:
start bit by micro-controller (ATTINY48 in my case)
sending slave address+w (in state 0x8), ACK from slave
sending command byte to slave (in state 0x18), ACK from slave
at this point (state 0x28) ISR must send a repeated start and jump to state 0x10
then sending Slave Adrress+R , ACK from slave
then in state 0x40 data will be read from slave, NACK to slave
in state 0x58 data is ready and copied to proper variable, stop bit will be transmitted.
I can set a flag every time I call the TC74 read function and check that flag inside the ISR, so instead of sending the stop bit after writing the data byte to the TC74, it will issue a repeated start bit. However I am not sure if this is the correct and standard method or not. Generally, in many states of I2C peripherals, the next state must be decided.
How should I instruct the ISR in each state to jump to the desired next state?

Related

STM32 I2C interrupt method requires a blocking while loop?

I have a Nucleo-F446RE, and I'm trying to get the I2C working with an IMU I have (LSM6DS33). I am using STM32CubeMX and checked out all the example code for my board which is related to I2C. Specifically I'll be talking about their 'I2C_TwoBoards_ComIT' example, but all their examples which use the interrupt method have this same quirk. Here is a snipped of their code from main.c:
/* The board sends the message and expects to receive it back */
do
{
/*##-2- Start the transmission process #####################################*/
/* While the I2C in reception process, user can transmit data through
"aTxBuffer" buffer */
if(HAL_I2C_Master_Transmit_IT(&I2cHandle, (uint16_t)I2C_ADDRESS, (uint8_t*)aTxBuffer, TXBUFFERSIZE)!= HAL_OK)
{
/* Error_Handler() function is called in case of error. */
Error_Handler();
}
/*##-3- Wait for the end of the transfer ###################################*/
/* Before starting a new communication transfer, you need to check the current
state of the peripheral; if it’s busy you need to wait for the end of current
transfer before starting a new one.
For simplicity reasons, this example is just waiting till the end of the
transfer, but application may perform other tasks while transfer operation
is ongoing. */
while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY)
{
}
/* When Acknowledge failure occurs (Slave don't acknowledge its address)
Master restarts communication */
}
while(HAL_I2C_GetError(&I2cHandle) == HAL_I2C_ERROR_AF);
Under comment ##-3- they explain that unless we wait for the I2C state to be ready again, after sending a command, the next command will overwrite the previous one, so they use a while loop which waits for the I2C state to be 'ready' before continuing.
Isn't this a very inefficient way to use an interrupt, and no different from using the standard polling method? Both block the main code, so what's the purpose of the interrupt?
In my personal example, I want to collect the accelerometer/gyroscope data at the 1.66 kHz rate which the IMU is capable of. I use a 2kHz timer to send an I2C command to read the acc/gyr data-ready register, and if the data is ready for either sensor I read their 6 bytes to get the x/y/z plane information. Using the polling method is too slow as blocking the code at a rate of 2kHz is not inefficient, but the interrupt method doesn't seem to be any faster as I still need to hang the system during the aforementioned while loop to check if I2C is ready for another command. What am I missing here?
Is this (the example you provided) an efficient way of doing things? No. Can blocking part be avoided? Yes. It's only a small example, a proof of concept, so there is some blocking in there. You should look deeper at why it is there and how can you implement what it does without blocking.
The point of that blocking part is to not start an I2C communication while another I2C communication is in progress. The problem is that while your line of code to send something over I2C has already been executed, the data is still being physically sent over the line, just because your MCU is much faster than I2C. You need to wait until I2C line is idle and available for transmission.
How to achieve that with interrupts and not waste cycles and processing time? Given in your case you can easily estimate the amount of data per each transmission, there is no probem to estimate how much time every transmission will take given your I2C speed. Since you're smartly and correctly using timer to schedule regular transmissions, you should be able to set the timer in such a way that by the next timer interrupt, which will send data, your previous communication has already ended.
For example, if you set the timer to 1Hz to start transmission, you can obviously be sure that by the next interrupt all the communication has happened. You don't need to poll anything at all.
I don't see much point in I2C-polling the IC at 2kHz if it produces data at 1.6kHz. You will have uneven time periods between samples, some data will be very fresh, while some data will come with little delay, plus there will be communication without data ready. It would be better to poll it at something like 1.5-1.6kHz and just expect data to always be there. Of course, given the communication fits into 1.5kHz period, which requires some napkin math.

Does HAL_SPI_Transmit() discard received data?

Suppose I have two STM boards with a full duplex SPI connection (one is master, one is slave), and suppose I use HAL_SPI_Transmit() and HAL_SPI_Receive() on each end for the communication.
Suppose further that I want the communication to consist of a series of single-byte command-and-response transactions: master sends command A, slave receives it and then sends response A; master sends command B, slave receives it and then sends response B, and so on.
When the master calls HAL_SPI_Transmit(), the nature of SPI means that while it clocks out the first byte over the MOSI line, it is simultaneously clocking in a byte over the MISO line. The master would then call HAL_SPI_Receive() to furnish clocks for the slave to do the transmitting of its response. My question: What is the result of the master's HAL_SPI_Receive() call? Is it the byte that was simultaneously clocked in during the master's transmit, or is is what the slave transmitted afterwards?
In other words, does the data that is implicitly clocked in during HAL_SPI_Transmit() get "discarded"? I'm thinking it must, because otherwise we should always use the HAL_SPI_TransmitReceive() call and ignore the received part.
(Likewise, when HAL_SPI_Receive() is called, what is clocked OUT, which will be seen on the other end?)
Addendum: Please don't say "Don't use HAL". I'm trying to understand how this works. I can move away from HAL later--for now, I'm a beginner and want to keep it simple. I fully recognize the shortcomings of HAL. Nonetheless, HAL exists and is commonly used.
Yes, if you only use HAL_SPI_Transmit() to send data, the received data at the same clocked event gets discarded.
As an alternative, use HAL_SPI_TransmitReceive() to send data and receive data at the same clock events. You would need to provide two arrays, one that contains data that will be sent, and the other array will be populated when bytes are received at the same clock events.
E.g. if your STM32 SPI Slave wishes to send data to a master when the master plans to send 4 clock bytes to it (master sends 0xFF byte to retrieve a byte from slave), using HAL_SPI_TransmitReceive() will let you send the data you wish to send on one array, and receive all the clocked bytes 0xFF on another array.
I never used HAL_SPI_Receive() before on its own, but the microcontroller that called that function can send any data as long as the clock signals are valid. If you use this function, you should assume on the other microcontroller that the data that gets sent must be ignored. You could also use a logic analyzer to trace the SPI data exchange between two microcontrollers when using HAL_SPI_Transmit() and HAL_SPI_Receive().

SPI DMA CIRCULAR Mode - stm32f4

Does anyone have a sample code of transfering data with SPI in DMA CIRCULAR mode for stm32?(16 bit)
With my code, master sends 16 bit data and in the next cycle receives the answer. But this transaction done with one cycle delay.
SPI is supposed to work that way.
When the SPI data register is written the first time, it starts sending the data, and immediately signals the DMA controller that it's ready for the next data word. Now there are two data words down in the transmitter, when it has barely started receiving the first one. When the first outgoing word is completely transmitted, and the first incoming word is completely received (these happen almost simultaneously), SPI starts sending the second word already in the data register, signals the transmit DMA channel that it's ready for the third data word, about the same time it also signals the receiving channel that the first incoming data word is ready.

STM32F4 DMA can work in parallel?

I'm working on an appolication that requires 3x SPI (I'm master in all of them) and SDIO interface, using STM32F446.
2 of the SPIs (SPI1 and SPI2) are sensors that need to be read every 1ms. For SPI1 I need to write 1 byte and the response to that will be the value. For SPI2 I need to write 1 byte and then read 6.
The third SPI (SPI3) and the SDIO are for communication/logging and both of them don't need to transmit data with a fixed period.
Looking at the STM32F46x manual , section 9, it doesn't look like I can trigger DMA transfers with peripherals interupts (that's too bad), but can I do the all thing like:
Timer interrupt every 1ms: inside ISR SPI1 and SPI2 DMA transfers are triggered. DMA transfer fills buffer with received sensor data;
Everytime I need to write to SDIO or SPI3 I start a DMA transfer with less priority then the ones at SPI1 and SPI2.
I'm guessing that SPI1 and SPI2 can perform at parallel since I have 2 DMA controllers and that, if they occur at the same time of SPI2 and SDIO, the later will be blocked until the controller is free. Is that right?
For SPI1 I need to write 1 byte and the response to that will be the
value. For SPI2 I need to write 1 byte and then read 6.
Note that with SPI, reads and writes occur simultaneously, you can read a byte by writing a dummy one, you should take this into account when setting the number of words to transmit.
DMA transfer fills buffer with received sensor data;
Some SPI slaves won't work properly unless you set CS high between transfers. If that's the case with your sensors, you should do that in the receiving DMA stream interrupt. If you are thinking of letting DMA fill up a large buffer automatically, that won't work in this case.
I'm guessing that SPI1 and SPI2 can perform at parallel since I have 2
DMA controllers and that, if they occur at the same time of SPI2 and
SDIO, the later will be blocked until the controller is free. Is that
right?
They will not be blocked, but interleaved as long as the higher priority transfer does not tie up the DMA bandwidth completely. No SPI transfer can do that, since SPI needs at least 16 clock cycles to transfer a single byte (at least 2 cycles/bit).

NACK and ACK responses on I2c bus

My recent project requires the use of i2c communication using a single master with multiple slaves. I know that with each data byte (actual data) sent by master,the slave responds with Nack\Ack(1,0).
I am confused that how this Nack and ACK are interpreted. I searched the web but i didn't got clear picture about this. My understanding is something like this.
ACK- I have successfully received the data. Send me more data.
NACK- I haven't received the data.Send again.
Is this something like this or I am wrong.
Please clarify and suggest the right answer.
Thanks
Amit kumar
You really should read the I2C specification here, but briefly, there are two different cases to consider for ACK/NACK:
After sending the slave address: when the I2C master sends the address of the slave to talk to (including the read/write bit), a slave which recognizes its address sends an ACK. This tells the master that the slave it is trying to reach is actually on the bus. If no slave devices recognize the address, the result is a NACK. In this case, the master must abort the request as there is no one to talk to. This is not generally something that can be fixed by retrying.
Within a transfer: after the side reading a byte (master on a receive or slave on a send) receives a byte, it must send an ACK. The major exception is if the receiver is controlling the number of bytes sent, it must send a NACK after the last byte to be sent. For example, on a slave-to-master transfer, the master must send a NACK just before sending a STOP condition to end the transfer. (This is required by the spec.)
It may also be that the receiver can send a NACK if there is an error; I don't remember if this is allowed by the spec.
But the bottom line is that a NACK either indicates a fatal condition which cannot be retried or is simply an indication of the end of a transfer.
BTW, the case where a receiving device needs more time to process is never indicated by a NACK. Instead, a slave device either does "clock stretching" (or the master simply delays generating the clock) or it uses a higher-layer protocol to request retrying.
Edit 6/8/19: As pointed out by #DavidLedger, there are I2C flash devices that use NACK to indicate that the flash is internally busy (e.g. completing a write operation). I went back to the I2C standard (see above) and found the following:
There are five conditions that lead to the generation of a NACK:
No receiver is present on the bus with the transmitted address so there is no device to respond with an acknowledge.
The receiver is unable to receive or transmit because it is performing some real-time function and is not ready to start
communication with the master.
During the transfer, the receiver gets data or commands that it does not understand.
During the transfer, the receiver cannot receive any more data bytes.
A master-receiver must signal the end of the transfer to the slave transmitter.
Therefore, these NACK conditions are valid per the standard.
Short delays, particularly within a single operation will normally use clock stretching but longer delays, particularly between operations, as well as invalid operations, my well produce a NACK.
I2C Protocol starts with a start bit followed by the slave address (7 bit address + 1 bit for Read/Write).
After sending the slave address Master releases the data bus(SDA line), put the line in high impedance state leaving it for slave to drive the line.
If address matches the slave address, slave pull the line low for the ACK.
If the line is not pull low by any of the slave, then Master consider it as NACK and sends the Stop bit or repeated start bit in next clock pulse to terminate the or restart the communication.
Besides this the NACK is also sent whenever receiver is not able to communicate or understand the data.
NACK is also used by master (receiver) to terminate the read flow once it has all the data followed by stop bit.