I2C read - repeated start needed? - i2c

I have a doubt regarding read operation in I2C, bit banging. The protocol which I am following for read as below:
Start-slave address with write-ack-register loc-ack-stop. ...... Start-slave address with read-ack-read data-stop.
I am reading data as FFh which is wrong.
My doubt is, before sending the another start, do in need to send stop or can continue the another start for reading data without stop, which actually is a repeated start. Does sending a stop bit or not makes any difference. Also can someone tell what can be the possible reason if data read is FFh. But I can guarantee that write operation is successful, after seeing the scope shot. Please guide me.
Thanks

The i2c protocol works like this
WRITE:
send START
write slave address with last bit as WRITE ACCESS(0)
write sub-address: this is usually the address of the register you what to write to; if not applicable skip to 4.
write data
send STOP
Each byte you write to the slave device should be answered with an ACK if the operation was successful.
READ:
send START
write slave address with last bit as WRITE ACCESS(0)
write sub-address: this is usually the address of the register you what to read from
send START (this is a second start condition - a restart)
write slave address with last bit as READ ACCESS(1)
read data
send STOP
All write and read operations (except the last read) are answered with a ACK if successful.
So in the case of a restart you don't send a second Stop.
As far as the 0xFF read result is concerned, you need to check the datasheet of the device, but some will return this value if the data you are trying to read is not available, yet!
Hope this helps.

I just had this issue and found the reason: if you receive FFh in reading all the time, you are missing the repeated start.

Related

STM32 bootloader failure to erase

I am writing an external bootloader for the STM32F730Z8 - (why? I need one windows code that can run the bootloader for the STM32, or use the STM32 to reprog a connected ATF1508 for my client). I've done this before, using info in AN3155 and AN2606. On lesser CPUs, this has had no difficulty (i.e. STM32L4P5). In this case, I try the same:
1-cycle \RESET & BOOT0 to boot to supervisor mode
2-autobaud successfully
3-send 0x00 to get the list of commands, successfully
4-send 01 to get the version and protection, successfully (vers 49, rp and nt both 0)
5-send 02 to get chip id (0x0452), successfully
6-send 0x73 to write-unprotect flash, successfully (i.e. receive back two ACK)
7-send 0x44 to begin an extended erase (intending only to erase sector 0).
This is where it fails. I get neither ACK nor NACK - it just times out. I don't even get to the second half of the extended-erase command where I send it the sector info. (On the STM32L4P5 it succeeds here easily and goes on to finish erasing, then to write code successfully.)
I've tried very long waits & repeat loops to wait for the ACK (many minutes). From past experience this should be fast, it is only the second stage where I tell it how much flash to erase that takes any significant time.
I've inspected the protection option areas of memory, at 0x1FFF0010, 0018, and they are unprotected, as per factory defaults.
I'm communicating over an FT231XS-R, using the D2XX driver calls. I can mess with the baud rates and such, but that only prevents it from autobauding...and we're doing that fine (9600/8/1/E). I've played with the D2XX SetTimeouts - if set too hasty that only screws up earlier commands. I'm wired to a 20 MHz crystal, and the application runs at 200 MHz, but my understanding is that the bootloader just runs at the internal RC clock rate.
I'm certainly missing something stupid, but I didn't see it in the documentation. Help?
Jeff Casey / Rockfield Research Inc. / Las Vegas, NV
Fixed, disregard.
The fineprint of AN3155 clued me in. On the description of the Write Unprotect command, it says that a system reset will be performed after completion. How did I miss this on the STM32L4P5? I just didn't read it. But why did it work then? In the really fine print next page, in a footnote to the flowchart, it says that they were just foolin'....system reset is only called for some (..list omitted..) and for other STM32 products no system reset is called for.
My earlier success had the following sequence:
reboot-supervisor
autobaud
get
gvrp
gid
wpun
xerase
wpun
write
verify
reboot-user
obviously that doesn't work for the F730. what works is:
reboot-super
autobaud
get
gvrp
gid
wpun
reboot-super
autobaud
get gvrp
gid
xerase
reboot-super
autobaud
get
gvrp
gid
write
verify
reboot-user
(obviously I can skip a few of the repeated steps, like get-id, but basically it needed a reboot and re-autobaud.)
note that i had to reboot-super a 3rd time...this was because the write attempt timed out after the xerase unless i went through the whole sequence again. funny, though, the spec doesn't say anything about resetting after an erase. i cross posted this question on the STM32 community site, and I'll do the same with this answer and ping them on this.
Thanks for reading, cheers. Jeff

Syncing of buffer-transmission with ESP32, I2S MEMS-mic and SD-card (FreeRTOS, PlatformIO, ESP-PROG)

i know this forum dislikes "open" questions like this, nevertheless i'd like somebody to help untie the knot in my head, much appreciated.
The goal is simple:
read a stereo 32bit 44100 S/s I2S signal from 2 adafruit sph0645 mics
create a wav-header and store the data onto an SD-card
I've been at this for a few days now and i know that this will be much more complicated than i originally thought. Main reason: signal quality. Like most tutorials on this subject the simplest "hello world" for these mics is a looped polling for I2S-samples. Poll, fill buffer, output via serial or write to SD-card. This returns a choppy, noisy, sped up version of RL-audio. The filling of the internal DMA-buffers can be seen as constant, but the rest is mostly chaos, so
how to i sync these DMA-buffers with the rest of my code?
From experience with the STM32 HAL i'd imagine some register which can be set to throw an interrupt whenever a buffer is full, or an event which can be sent between tasks via queues. Examples on this subject either poll in a main loop with mono an abysmal sample-rate and bit depth or use pages of overkill code and never adress what it does, "just copy and it works", not good. Does the ESP32-Arduino framework provide some way to to this properly? The espressif-documentation isn't something to look forward to, since some of their I2S interface functions don't even work (if you are researching this topic as well, you too might have noticed that i2s_read only returns zeros). Just a hint into the right direction would help, i'm writing my own code anyway. Interrupts? Events? Timers? Polling for full buffers? Only you might know.
have a good one, thx
Thanks to https://github.com/atomic14/ i now have an answer for a syncing-method which works very well. This method has been tried by https://esp32.com/viewtopic.php?t=12546 who also didn't fully understand what was going on: the espressif i2s-interface offers a flag stored in an event which is triggererd every time one of the specified dma-buffers has received a full set of data, ergo, is full. It looks like this:
while(<your condition>){
i2s_event_t evt;
if (xQueueReceive(<your queue>, &evt, portMAX_DELAY) == pdPASS){
if (evt.type == I2S_EVENT_RX_DONE){
size_t bytesRead = 0;
do{
//read data via i2s_read or i2s_read_bytes
} while (bytesRead > 0);
No data is stored in this queue, but rather a flag which can then be used to synchronize dma-filling and further buffering/calculating/sending the read data.
HOWEVER this only works if you install the i2s driver in a specific setup. Instead of using
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
in your setup, you can activate the "affinity" for events by passing a queue-handle and a lenght:
i2s_driver_install(I2S_NUM_0, &i2s_config, 4, &<your queue>);
hope this helps getting started, it sure did help me.

Cannot init NRF24L01+ registers using SPI and STM32F303

Am trying to initialize the NRF24L01+ registers using SPI but they always return 0x00.
According to the datasheet, Table 20 on page 51, all write commands will have a pattern of b001x xxxx, which i understood as having a 0x2x pattern.
In my snapshot below, i send the register value, for example register 0x00 will be sent as 0x20 indicating a write command to that register and then i send the value to be written on that register.
As you see on the MISO line, the value is 0x00 even when am trying to write a 0x08 which should be the default value according to page 57 of the datasheet.
I still dont know why its returning 0x00 even when i independently try to read the contents of that register later on without writing to it. I still get 0x00. The same applies to all other registers that am trying to re-init.
Anyone who has experienced this behaviour elsewhere or is it me that is having something wrong?
The NRF24 am trying to program here is this type from sparkfun
You are close. The datasheet shows write register as 001A AAAA and read as 000A AAAA, where the 5 A's represent the register you want to write to. The spec states that while the command is being sent (read, write, read payload, write payload, flush, activate, and so on), the device will return the status register. In your data, the device is responding with 0x0E, which is correct; decoded is is saying no errors and no data received or pending to transmit. If you want to see if the command you send was accepted, you need to first write the data and then read the data. For example, let's say we want to write the config register to enable the device as a receiver, 2 byte CRC with Rx interrupts enabled.
First, you would send 0b00100000 (0x20), 0b00111111 (0x3F). The device will respond with 0b00001110 (0x0e), 0b00000000 (0x00). This is what you are seeing. If you want to verify the configuration register, you need to then send 0b00000000 (0x00),which is the command to read the config register, then 0b00000000 (0x00), which is a dummy byte to clock out the data. The device will respond with 0x0e, which is the status, and then 0x3F assuming you configured as I did above.
Note that there are more commands than just reading and writing the registers, there are specific commands to fill and read the pipeline data.
Hope this helps.

UDP socket, select one of multiple clients

here's what I'm trying to do:
I have 4 clocks and one PC on the network. I (PC) want to get the time from any of the clocks.
The idea:
Every clock uses UDP Broadcast (broadcast because I don't know the PC's IP). The PC gets a first dataset(time) and from then on only looks at datasets from this clock. (To not get confused by slight timedifferences between the clocks)
Clocks=Clients:
- socket
- bind to port 1234
- sendto(broadcast,'1234')
PC=Server
- socket
- bind to port 1234
- recvfrom(data,client_addr) //extract client_addr from first received data
- connect(client_addr) //to only receive data from this client
- recvfrom()
1: Is this the correct way to do this? Or is there a better option?
2: What can I do, if I want more than one application on the PC to get the time-data? Can I just copy the code and use it? My impression was, that port 1234 is now blocked from the first application that gets the bind.
(I guess SO_REUSEADDR won't work because only ONE application then gets the data AND I don't know which one it is going to be)
Regards
1: Is this the correct way to do this?
Yes.
Or is there a better option?
Can't think of one off-hand.
2: What can I do, if I want more than one application on the PC to get the time-data?
Use SO_REUSEADDR.
Can I just copy the code and use it?
Yes.
My impression was, that port 1234 is now blocked from the first application that gets the bind.
No.
(I guess SO_REUSEADDR won't work because only ONE application then gets the data AND I don't know which one it is going to be)
Wrong guess. Why guess about it at all? Why not try it? Much more reliable than guessing, and quicker than asking questions here too.

Weird Winsock recv() slowdown

I'm writing a little VOIP app like Skype, which works quite good right now, but I've run into a very strange problem.
In one thread, I'm calling within a while(true) loop the winsock recv() function twice per run to get data from a socket.
The first call gets 2 bytes which will be casted into a (short) while the second call gets the rest of the message which looks like:
Complete Message: [2 Byte Header | Message, length determined by the 2Byte Header]
These packets are round about 49/sec which will be round about 3000bytes/sec.
The content of these packets is audio-data that gets converted into wave.
With ioctlsocket() I determine wether there is some data on the socket or not at each "message" I receive (2byte+data). If there's something on the socket right after I received a message within the while(true) loop of the thread, the message will be received, but thrown away to work against upstacking latency.
This concept works very well, but here's the problem:
While my VOIP program is running and when I parallely download (e.g. via browser) a file, there always gets too much data stacked on the socket, because while downloading, the recv() loop seems actually to slow down. This happens in every download/upload situation besides the actual voip up/download.
I don't know where this behaviour comes from, but when I actually cancel every up/download besides the voip traffic of my application, my apps works again perfectly.
If the program runs perfectly, the ioctlsocket() function writes 0 into the bytesLeft var, defined within the class where the receive function comes from.
Does somebody know where this comes from? I'll attach my receive function down below:
std::string D_SOCKETS::receive_message(){
recv(ClientSocket,(char*)&val,sizeof(val),MSG_WAITALL);
receivedBytes = recv(ClientSocket,buffer,val,MSG_WAITALL);
if (receivedBytes != val){
printf("SHORT: %d PAKET: %d ERROR: %d",val,receivedBytes,WSAGetLastError());
exit(128);
}
ioctlsocket(ClientSocket,FIONREAD,&bytesLeft);
cout<<"Bytes left on the Socket:"<<bytesLeft<<endl;
if(bytesLeft>20)
{
// message gets received, but ignored/thrown away to throw away
return std::string();
}
else
return std::string(buffer,receivedBytes);}
There is no need to use ioctlsocket() to discard data. That would indicate a bug in your protocol design. Assuming you are using TCP (you did not say), there should not be any left over data if your 2byte header is always accurate. After reading the 2byte header and then reading the specified number of bytes, the next bytes you receive after that constitute your next message and should not be discarded simply because it exists.
The fact that ioctlsocket() reports more bytes available means that you are receiving messages faster than you are reading them from the socket. Make your reading code run faster, don't throw away good data due to your slowness.
Your reading model is not efficient. Instead of reading 2 bytes, then X bytes, then 2 bytes, and so on, you should instead use a larger buffer to read more raw data from the socket at one time (use ioctlsocket() to know how many bytes are available, and then read at least that many bytes at one time and append them to the end of your buffer), and then parse as many complete messages are in the buffer before then reading more raw data from the socket again. The more data you can read at a time, the faster you can receive data.
To help speed up the code even more, don't process the messages inside the loop directly, either. Do the processing in another thread instead. Have the reading loop put complete messages in a queue and go back to reading, and then have a processing thread pull from the queue whenever messages are available for processing.