How can I read two bytes from two Registers in a Device within i2c? - byte

Currently - I am following the below steps to read multiple bytes from multiple registers -
Make a START sequence
Send 1010XXX0, where XXX is the direction of the IC to use, wait for ACK
Send the low byte_0 of the register address to be read, wait for ACK
Send the high byte_0 of the register address to be read, wait for ACK
Send the low byte_0 of the register address to be read, wait for ACK
Send the high byte_1 of the register address to be read, wait for ACK
Make a START sequence
Send 1010XXX1, where XXX is the direction of the IC to use, wait for ACK
Read byte_0, send an ACK to the memory
Read byte_1, send an ACK to the memory
Send a nack
When no more bytes need to be read, send a STOP sequence
. Example I2C Read from Slave Device's Register
However, I am not able to read two bytes, and only one byte can be read.
What is the correct process to read both the bytes from both the 0x0000 and 0x0001 register?

Refering to the I2C-bus specification from NXP:
General comment: There is no XXX direction specification in the I2C Addressing. All 7 bits are the address of the slave. The eighth bit tells the device whether this will be a write (0, master write bytes to slave) or a read (1, slave writes bytes to master) operation.
Having said that, reading two bytes at 0x0000 and 0x0001 should work like that:
Tell device to go to the first byte:
Start condition (S)
Slave adress (7 bits, XXXXXXX)
Write intent (1 bit, "0")
ACK by slave
Send first adress byte to device (8 bits, "00000000")
ACK by slave
Send second adress byte to device (8 bits, "00000000")
ACK by slave
Now, the slave should be pointing at first byte you want to read, i.e. 0x0000. From here, you should be able to successively read both bytes from the device
Repeated Start condition (same as Start)
Slave adress (7 bits, XXXXXXX)
Read intent (1 bit, "1")
ACK by slave
Read first byte from slave (the slave should now automatically jump to the next byte)
ACK by master
Read second byte from slave
NACK by master (to end transfer)
Stop condition (P)
Here's an image of the communication flow described above:

Related

Reveng to find out CRC algorithm in closed protocol

I have one machine with closed protocol and another device "gateway Modbus" from the same manufacter. This gateway convert this protocol to RS-485 Modbus.
When I send a command packet (modbus function 16) to gateway, gateway send (converted) specific packet to the machine and when I inject this packet over simple UART communication, machine can understand and change values too. I create a list with some cloned commands, but I need to know how CRC/checksum/etc is calculed (I think) to create custom packets.
I already used RevEng tool (https://reveng.sourceforge.io/) and CRCcalculator (https://crccalc.com/) trying to find some common crc algorithm with cloned packets, but none worked.
Some cloned packets, where 2 last bytes is CRC/etc. In this packets I changed the temperature value from 0x11 to 0x15 and last 2 bytes changed too (maybe crc/checksum/etc):
9A56F1FE0EB9001100000100641C
9A56F1FE0EB90012000001006720
9A56F1FE0EB90013000001006620
9A56F1FE0EB9001400000100611C
9A56F1FE0EB9001500000100601C
RevEng output:
./reveng -w 16 -l -s 9A56F1FE0EB9001100000100641C 9A56F1FE0EB90012000001006720 9A56F1FE0EB90013000001006620 9A56F1FE0EB9001400000100611C 9A56F1FE0EB9001500000100601C
./reveng: no models found
Someone can help me?
It's not a CRC. The second-to-last byte is the exclusive-or sum of the preceding bytes. I'm not sure what the last byte is, but since it is only taking on two different values in your example, it does not appear to be part of a check value. Or if it is, it's a rather ineffective check value algorithm.

Esp32 Micropython Max31865 Spi connection and data read

I need to read temperature data with using MAX31865 SPI communication. First of all, I tried to read 4 byte data:
import machine
import ubinascii
spi = machine.SPI(1, baudrate=5000000, polarity=0, phase=0)
#baudrate controls the speed of the clock line in hertz.
#polarity controls the polarity of the clock line, i.e. if it's idle at a low or high level.
#phase controls the phase of the clock line, i.e. when data is read and written during a clock cycle
cs = machine.Pin(15, machine.Pin.OUT)
cs.off()
cs.on()
data = spi.read(4)
cs.off()
print(ubinascii.hexlify(data))
I tried many times with different codes but result is always similar b'00000000'.
I am using ESP32 WROOM.
I used this pins:
ESP32 : D12 - D14 - 3V3 - GND - D15
Max31865: SDO - CLK - VIN - GND - CS
I am new on micropython and esp32.
I don't know what should I do. Is there any suggestions , recommended tutorials or idea?
Short answer: see if you can use CircuitPython and its drivers for MAX31865.
Long answer: a bunch of stuff. I suspect you've been following the Adafruit tutorial for MAX31855, but its SPI interface is very different from the MAX31865.
Your SPI connection is missing the SDI pin. You have to connect it, as communication is bidirectional. Also, I suggest using the default SPI pinout on ESP32 side as described in the micropython documetation for ESP32.
The SPI startup looks to be missing stuff. Looking at the SPI documentation a call to machine.SPI() requires that you assign values to arguments sck, mosi, miso. Those would probably be the pins on ESP32 side where you've connected SCLK, SDI, SDO on MAX31865 (note mosi means "master out, slave in" and miso is "master in, slave out").
The chip select signal on the MAX is inverted (that's what the line above CS input in the datasheet means). You have to set it low to activate the chip and high to disable it.
You can't just read data out of the chip, it has a protocol you must follow. First you have to request a temperature-to-resistance conversion from the chip. The datasheet for your chip explains how to do that, the relevant info starts on page 13 (it's a bit difficult to read for a beginner, but try anyway as it's the authoritative source of information for this chip). On a high level, it works like this:
Write to Configuration register a value which initiates the conversion.
Wait for the conversion to complete.
Read from the RTD (Resistance-To-Digital) registers to get the conversion result.
Calculate the temperature value from the conversion result.
The code might be closer to this (not tested, and very likely to not work off the bat - but it should convey the idea):
import ubinascii, time
from machine import Pin, SPI
cs = Pin(15, Pin.OUT)
# Assuming you've rewired according to default SPI pinout
spi = machine.SPI(1, baudrate=100000, polarity=0, phase=0, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
# Enable chip
cs.off()
# Prime a 1-shot read by writing 0x40 to Configration register 0x00
spi.write(b'\x00\x40')
# Wait for conversion to complete (up to 66 ms)
time.sleep_ms(100)
# Select the RTD MSBs register (0x01) and read 1 byte from it
spi.write(b'\x01')
msb = spi.read(1)
# Select the RTD LSBs register (0x02) and read 1 byte from it
spi.write(b'\x02')
lsb = spi.read(1)
# Disable chip
cs.on()
# Join the 2 bytes
result = msb * 256 + lsb
print(ubinascii.hexlify(result))
Convert result to temperature according to section "Converting RTD Data Register
Values to Temperature" in datasheet.
Side note 1: here spi = machine.SPI(1, baudrate=5000000, polarity=0, phase=0) you've configured a baud rate of 5MHz which is the maximum for this chip. Depending on how you've connected your devices, it may not work. The SPI protocol is synchronous and driven by master device, so you can set any baud rate you want. Start with a much, much lower value, maybe 100KHz or so. Increase this after you've figured out how to talk to the chip.
Side note 2: if you want your conversion result faster than the 100ms sleep in my code, connect the DRDY line from MAX to ESP32 and wait for it to go low. This means the conversion is finished and you can read out the result immediately.

Windows CE 6.0 : Serial port IRQ 6, 3E8 transfers only 16 bytes

I have configured our custom BSP to have 4 COM ports.
Out of these 3 COM ports work fine.
I have issue with the below COM port:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial3]
"SysIntr"=dword:16
"IoBase"=dword:03E8
"IoLen"=dword:8
"DeviceArrayIndex"=dword:2
"Prefix"="COM"
"IClass"="{CC5195AC-BA49-48a0-BE17-DF6D1B0173DD}"
"Dll"="Com16550.Dll"
"Order"=dword:0
"Flags"=dword:10 ; User MOde: DEVFLAGS_LOAD_AS_USERPROC
Any transmission of more than 16 bytes is truncated. On debugging we found that after transmitting first 16 bytes, it waits for IIR(Interrupt Identification Register) "Transmitter Holding Register Empty Interrupt" event to occur.
But this does not occurs.
Any thoughts on how to proceed with this.
I seem to remember that 'modern' UARTS have a 16 byte transmit (and receive) buffer to allow fewer interrupts to the main CPU. This would explain why you can transmit 16 bytes before it stops.
As for the reason your custom board doesn't interrupt, I would assume you haven't wired up the interrupt line from the UART to your main processor.
It was a BIOS issue and it got resolved after updating the BIOS

When should a USB device send a ZLP on a bulk pipe?

I'm writing firmware for a USB 2.0 full speed device that communicates with a WinUSB host, with one Bulk Pipe in each direction. When should the device send a zero-length packet (ZLP) to terminate an IN transfer, and how does it know that it should?
Section 5.8.3 of the USB 2.0 spec says:
A bulk transfer is complete when the endpoint does one of the following:
Has transferred exactly the amount of data expected
Transfers a packet with a payload size less than wMaxPacketSize or transfers a zero-length packet [ZLP]
I interpret this to mean that a ZLP should be sent when the transfer size is an integer multiple of the max packet size, and the "expected" size of the transfer is greater than the actual size (i.e. what is available to be sent). But how does the recipient know what's expected?
For instance, I'm using the WinUSBNet wrapper in C#. When I read from the pipe like this
int bytesRead;
buffer = new byte[128];
try
{
bytesRead = m_PipeIN.Read(buffer);
buffer = buffer.Take(bytesRead).ToArray();
}
the library calls WinUsb_ReadPipe() like this:
WinUsb_ReadPipe(InterfaceHandle(ifaceIndex),
pipeID,
pBuffer + offset,
(uint)bytesToRead,
out bytesRead,
IntPtr.Zero);
Suppose the device has exactly 128 bytes to send, and max packet size is 64 bytes. How does the device determine what the host is "expecting", thus whether it should send a ZLP to terminate the transfer?
(Similar to this question, but that one is about control pipes. I'm asking about bulk pipes.)
Explanation of the spec:
Case 1
Has transferred exactly the amount of data expected
This means that if the host is expecting X amount of bytes, and you send exactly X amount of bytes, the transfer stops right there. MPS and ZLP don't play into it.
Case 2
Transfers a packet with a payload size less than wMaxPacketSize or transfers a zero-length packet [ZLP]
This means that if the host is expecting X bytes but you want to send only Y bytes, where Y < X, the transfer is complete as soon as you do a "short" packet, a packet less the MPS. If Y bytes is a multiple of MPS, then you would have to do a ZLP.
Example 1 (no ZLP)
MPS = 512, the host expects 8192 bytes.
You want to send only 1500 bytes. The payload would go over in 3 packets like this:
Packet 0: [512 bytes] MPS
Packet 1: [512 bytes] MPS
Packet 2: [476 bytes] short packet
When the host gets the short packet, it knows the transfer is complete, and won't continue asking for more packets for the transfer.
Example 2 (with ZLP)
MPS = 512, the host expects 8192 bytes.
You want to send only 2048 bytes. The payload would go over in 4 packets like this:
Packet 0: [512 bytes] MPS
Packet 1: [512 bytes] MPS
Packet 2: [512 bytes] MPS
Packet 3: [512 bytes] MPS
At this point, the host has received 4 MPS-sized packets so it doesn't know the transfer is complete. So it will continue to request packets from the device.
Packet 4: [0 bytes] short packet (ZLP)
When the host gets the short packet, it knows the transfer is complete, and won't continue asking for more packets for the transfer.
Determining Transfer Size
You may be wondering how to determine the "expected" amount of bytes since BULK transfers do not have a length like CTRL transfers do. This is determined entirely by the higher-level protocol that specifies how to do transfers on the BULK pipes. The host and device both follow this protocol and thus they are in sync about how much data to transfer at any given time.
This protocol is typically specified by a class specification, like the mass-storage class protocol, or it could be some very simple protocol of your own design.
Transfers a packet with a payload size less than wMaxPacketSize or transfers a zero-length packet [ZLP]
a ZLP has to be send when the length of payload data is exactly an integer multiple of wMaxPacketSize
The USB spec defines that if the last packet of a bulk transfer has
the exact size of the endpoint max packet size, the whole transfer
must be terminated by a zero length urb.
If apps don't sent this in such a situation libusb times out and the
initial urb is never sent resulting in a broken application.
All Kernel drivers use the URB_ZERO_PACKET to comply to the spec
correctly.
source: http://libusb.org/ticket/6
in case that data length is exactly an integer multiple of wMaxPacketSize
the first ending condition packetSize < wMaxPacketSize does not apply because in this case packetSize = wMaxPacketSize.
so to indicate the information that the last packet has been send you need a ZLP, else the other side would expect more data
there are several other situations when ZLPs are sent see i.e. USB in a nutshell website

how to send different length sentence in UART protocol

I have build a UART module, 1stop bit 8 data bits 1 start bit, in vhdl which works good (checked with computer program and usb-to-ttl adapter).
I have EMIC2 which use and it works with UART also .
my goal is to have a bigger module which will contain the uart module and will send full messages out in uart .
I want to have like 5 messages to be selected ,each with a different length, and each messages should be send to the uart module 1 byte at a time untill the end of the message .
I thought to do it with 5 different size FIFOs and to have a mux to selected between them, and each on each fifo ill enter the message byte byte and run on it .
But I wanted to ask if there is maybe a easier way to do it ?
Also I wanted to ask if there is a way to initialization a fifo ?

Resources