Does HAL_SPI_Transmit() discard received data? - stm32

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().

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.

Omnetpp application sends multiple streams

Let's say I have a car with different sensors: several cameras, LIDAR and so on, the data from this sensors are going to be send to some host over 5G network (omnetpp + inet + simu5g). For video it is like 5000 packets 1400 bytes each, for lidar 7500 packets 1240 bytes and so on. Each flow is encoded in UDP packets.
So in omnetpp module in handleMessage method I have two sentTo calls, each is scheduled "as soon as possible", i.e., with no delay - that corresponds to the idea of multiple parallel streaming. How does omnetpp handle situations, when it needs to send two different packets at the same time from the same module to the same module (some client, which receives sensor data streams)? Does it create some inner buffer on the sender or receiver side, therefore allowing really only one packet sending per handleMessage call or is it wrong? I want to optimize data transmission and play with packet sizes and maybe with sending intervals, so I want to know, how omnetpp handles multiple streaming at the same time, because if it actually buffers, maybe than it makes sense to form a single package from multiple streams, each such package will consist of a certain amount of data from each stream.
There is some confusion here that needs to be clarified first:
OMNeT++ is a discrete event simulator framework. An OMNeT++ model contains modules that communicate with each other, using OMNeT++ API calls like sendTo() and handleMessage(). Any call of the sendTo() method just queues the provided message into the future event queue (an internal, time ordered queue). So if you send more than one packet in a single handleMessage() method, they will be queued in that order. The packets will be delivered one by one to the requested destination modules when the requested simulation time is reached. So you can send as many packets as you wish and those packets will be delivered one by one to the destination's handleMessage() method. But beware! Even if the different packets will be delivered one by one sequentially in the program's logic, they can still be delivered simultaneously considering the simulation time. There are two time concepts here: real-time that describes the execution order of the code and simulation-time which describes the time passes from the point of the simulated system. That's why, while OMNeT++ is a single threaded application that runs each events sequentially it still can simulate infinite number of parallel running systems.
BUT:
You are not modeling directly with OMNeT++ modules, but rather using INET Framework which is a model directly created to simulate internet protocols and networks. INET's core entity is a node which is something that has network interface(s) (and queues belonging to them). Transmission between nodes are properly modeled and only a single packet can travel on an ethernet line at a time. Other packets must queue in the network interface queue and wait for an opportunity to be delivered from there.
This is actually the core of the problem for Time Sensitive Networks: given a lot of pre-defined data streams in a network, how the various packets interfere and affect each other and how they change the delay and jitter statistics of various streams at the destination, Plus, how you can configure the source and network gate scheduling to achieve some desired upper bounds on those statistics.
The INET master branch (to be released as INET 4.4) contains a lot TSN code, so I highly recommend to try to use it if you want to model in vehicle networks.
If you are not interested in the in-vehicle communication, bit rather want to stream some data over 5G, then TSN is not your interest, but you should NOT start to multiplex/demultiplex data streams at application level. The communication layers below your UDP application will fragment/defragment and queue the packets exactly how it is done in the real world. You will not gain anything by doing mux/demux at application layer.

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.

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.

UDR (UART data register)issues

I can't understand the meaning of the following "The USART Transmit Data buffer register (TXB) and the USART Receive Data buffer register (RXB) share the same I/O address" there is two data register .how they share the same address ?
Now it's clear
From the diagram you see that The transmitter and receiver share the UDR (UART Data Register). Actually they only share the UDR address: The "real" register is divided into the transmitter and receiver register so that received data cannot overwrite data being written into the transmit register. Consequently you can't read back data you wrote into the transmitter register.
The register address is the same for both TXB and RBX and the actual addressed register is determined by the modality in which the UART is (reading or writing mode). This is depended on the actual implementation, but usually it consist in setting one or two more pins.
You can consider UDR register as the buffer between TXD and RXD registers.
As you know UART is sent bit by bit in the bus, While recieving the bits is entering the RXD register, when all the byte is being recieved it copied to UDR register and the flag is raised, now you should read the UDR register and if you write to it you will lose the recieved byte!!
By the same way in transmission, you write the a byte in UDR then it moved to TXD then output from registerbit by bit and the UDR is empty during transmission.
That's why there is interrupt for UDR, when the UDR becomes empty, and interrupt for TXD, when trasnmission is completed.