I am working on a react-native Android app using react-native-ble-plx for BTLE support, and Windows 10 using the .NET API Windows.Devices.Bluetooth.GenericAttributeProfile for the GATT server/peripheral.
When I add any "ServiceData" to the advertising payload in the Windows GATT service, the scanned device's 'serviceData' payload is always null in the react-native client.
In the Windows 10 server, if the GattServiceProviderAdvertisingParameters.ServiceData property is not null, then the service advertisement status is GattServiceProviderAdvertisementStatus.StartedWithoutAllAdvertisementData. (When leaving 'ServiceData' set to null, it is GattServiceProviderAdvertisementStatus.Started, as expected).
Using the Silicon Labs "EFR Connect" app in android, it also does not show any ServiceData for the device in the advertising packet.
Using WireShark with BTVS to inspect the packets on the Windows machine, it does show the Service Data bytes, and the controller shows a 'Success' response.
Here is the code where I set up the ServiceData in Windows:
...
GattServiceProviderAdvertisingParameters advParameters = new GattServiceProviderAdvertisingParameters
{
IsConnectable = _peripheralSupported,
IsDiscoverable = true,
ServiceData = GetServiceData().AsBuffer()
};
_serviceProvider.AdvertisementStatusChanged += ServiceProvider_AdvertisementStatusChanged;
_serviceProvider.StartAdvertising(advParameters);
...
private byte[] GetServiceData()
{
var flagsData = new List<byte> { 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
flagsData.AddRange(new List<byte>(Encoding.ASCII.GetBytes("ABCDEFGHIJKLMNOP")));
return flagsData.ToArray();
}
Here is the code in the react-native scanner:
public scanDevices(
timeoutSeconds: number,
listener: (error: string | null, scannedDevice: IPhoenixDevice | null) => void,
): void {
console.log('Entered PhoenixDeviceManager.scanDevices');
this.isScanning = true;
try {
this.scannedDevices.length = 0; // Clear array of devices
this.bleManager.startDeviceScan(this.serviceUUIDs, null, (error, scannedDevice) => {
console.log('In device scan callback');
if (error) {
console.warn(error);
listener(`Error message: ${error.message}, reason: ${error.reason}`, null);
}
if (!scannedDevice) {
console.log('scannedDevice is null');
} else if (!this.scannedDevices.some((d) => d.id === scannedDevice.id)) {
this.scannedDevices.push(scannedDevice);
listener(null, new PhoenixDevice(scannedDevice.id, scannedDevice.name));
console.log(
`Device discovered, id: ${scannedDevice.id}, name: ${scannedDevice.name}, localName: ${scannedDevice.localName}, serviceData: ${scannedDevice.serviceData}`,
);
}
});
const timeoutMs = timeoutSeconds * 1000;
// stop scanning devices after specified number of seconds
setTimeout(() => {
this.stopScanning();
}, timeoutMs);
} catch (error) {
console.error(error);
this.stopScanning();
}
}
Here is the WireShark trace running on Windows 10 showing the packet containing the ServiceData (and the Success response):
Frame 499: 84 bytes on wire (672 bits), 84 bytes captured (672 bits) on interface TCP#127.0.0.1:24352, id 0
Bluetooth
Bluetooth HCI H4
Bluetooth HCI Command - LE Set Extended Advertising Data
Command Opcode: LE Set Extended Advertising Data (0x2037)
Parameter Total Length: 80
Advertising Handle: 0x02
Data Operation: Complete scan response data (0x03)
Fragment Preference: The Controller should not fragment or should minimize fragmentation of Host data (0x01)
Data Length: 76
Advertising Data
Flags
Length: 2
Type: Flags (0x01)
000. .... = Reserved: 0x0
...1 .... = Simultaneous LE and BR/EDR to Same Device Capable (Host): true (0x1)
.... 1... = Simultaneous LE and BR/EDR to Same Device Capable (Controller): true (0x1)
.... .0.. = BR/EDR Not Supported: false (0x0)
.... ..1. = LE General Discoverable Mode: true (0x1)
.... ...0 = LE Limited Discoverable Mode: false (0x0)
16-bit Service Class UUIDs
Length: 3
Type: 16-bit Service Class UUIDs (0x03)
UUID 16: Device Information (0x180a)
128-bit Service Class UUIDs
Length: 17
Type: 128-bit Service Class UUIDs (0x07)
Custom UUID: caecface-e1d9-11e6-bf01-fe55135034f0 (Unknown)
Service Data - 128 bit UUID
Length: 50
Type: Service Data - 128 bit UUID (0x21)
Custom UUID: caecface-e1d9-11e6-bf01-fe55135034f0 (Unknown)
Service Data: ffff0000000000000000000000000000004142434445464748494a4b4c4d4e4f50
[Response in frame: 500]
[Command-Response Delta: 1.889ms]
Frame 500: 7 bytes on wire (56 bits), 7 bytes captured (56 bits) on interface TCP#127.0.0.1:24352, id 0
Bluetooth
Bluetooth HCI H4
Bluetooth HCI Event - Command Complete
Event Code: Command Complete (0x0e)
Parameter Total Length: 4
Number of Allowed Command Packets: 1
Command Opcode: LE Set Extended Advertising Data (0x2037)
0010 00.. .... .... = Opcode Group Field: LE Controller Commands (0x08)
.... ..00 0011 0111 = Opcode Command Field: LE Set Extended Advertising Data (0x037)
Status: Success (0x00)
[Command in frame: 499]
[Command-Response Delta: 1.889ms]
I've also tried using the exact code verbatim in this example and it has the exact same problem:
https://github.com/ProH4Ck/treadmill-bridge/blob/98e683e2380178319972af522d9251f44350a448/src/TreadmillBridge/Services/VirtualTreadmill/VirtualTreadmillService.cs#L90
Does anyone know what the problem might be?
Related
I am trying to get USB device code working on my stm32f401 microcontroller. So far, I'm able to read the packets from the host, send the first device request, receive and apply the assigned address. After that, the host requests for the device descriptor again, and my device doesn't response to that for some reason. I've been fighting this issue for weeks now, seems like I need help with it.
In my code, after initializing the peripherals, I set up my endpoint 0 and set its Tx FIFO size to 16. When the device receives a packet, it reads the packet status and reads the packet content in function setup_packet_handler(). This function prints the content word by word:
uint32_t data = *fifo;
printf("Rx from FIFO: 0x%08x\n", data);
void rxflvl_handler() {
uint32_t packet_status = USB_OTG_FS->GRXSTSP;
uint8_t endpoint_number = (packet_status & USB_OTG_GRXSTSP_EPNUM_Msk) >> USB_OTG_GRXSTSP_EPNUM_Pos;
uint16_t bcnt = (packet_status & USB_OTG_GRXSTSP_BCNT_Msk) >> USB_OTG_GRXSTSP_BCNT_Pos;
uint16_t pktsts = (packet_status & USB_OTG_GRXSTSP_PKTSTS_Msk) >> USB_OTG_GRXSTSP_PKTSTS_Pos;
printf("Received packet of status 0x%02x\n", pktsts);
switch (pktsts) {
case 0x06: // SETUP packet (includes data)
setup_packet_handler(endpoint_number, bcnt);
break;
case 0x02: // OUT packet (includes data)
break;
case 0x04: // SETUP stage has completed
case 0x03: // OUT transfer has completed
// Re-enable the endpoint
OUT_ENDPOINT(endpoint_number)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
OUT_ENDPOINT(endpoint_number)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA;
break;
}
}
My main() function watches the current number of packets to send and free space of the Tx FIFO for endpoint 0:
int main(void)
{
/* Pins initialization */
/* USB initialization */
in_packets = (in_endpoint->DIEPTSIZ & USB_OTG_DIEPTSIZ_PKTCNT_Msk) >> USB_OTG_DIEPTSIZ_PKTCNT_Pos;
fifo_space = in_endpoint->DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV_Msk;
printf("FIFO free space: %i\n", fifo_space);
while (1)
{
// Checking for USB interrupts
usb_poll();
// Notify if packets number changed
uint32_t npkts = (in_endpoint->DIEPTSIZ & USB_OTG_DIEPTSIZ_PKTCNT_Msk) >> USB_OTG_DIEPTSIZ_PKTCNT_Pos;
if (npkts != in_packets) {
printf("Packets number update: %i\n", npkts);
in_packets = npkts;
}
// Notify if FIFO space changed
uint16_t new_space = in_endpoint->DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV_Msk;
if (new_space != fifo_space) {
fifo_space = new_space;
printf("FIFO free space: %i\n", new_space);
}
}
}
Now the broken part, the code which sends the device descriptor. The function handle_descriptor_request() is called when the device descriptor request is received.
The function sets the size to transmit to 18; packet count to 3 (endpoint 0 max packet size is configured to 8); enables the endpoint and fills the FIFO. After that, prints the FIFO free space, to ensure it has decreased.
void handle_descriptor_request(void) {
printf("Received descriptor request\n");
uint32_t* fifo = (USB_OTG_FS_PERIPH_BASE + USB_OTG_FIFO_BASE +
0 * 0x1000);
USB_OTG_INEndpointTypeDef* in_endpoint = (USB_OTG_INEndpointTypeDef*)(
USB_OTG_FS_PERIPH_BASE +
USB_OTG_IN_ENDPOINT_BASE +
0
);
// flush_txfifo(0);
// in_endpoint->DIEPTSIZ = 0;
// in_endpoint->DIEPCTL |= USB_OTG_DIEPCTL_SNAK;
// in_endpoint->DIEPCTL |= USB_OTG_DIEPCTL_EPDIS;
printf("Manual PKTCNT to 3\n");
// Set Tx size to 18
in_endpoint->DIEPTSIZ &= ~USB_OTG_DIEPTSIZ_XFRSIZ_Msk;
in_endpoint->DIEPTSIZ &= ~USB_OTG_DIEPTSIZ_PKTCNT_Msk;
in_endpoint->DIEPTSIZ |= 18 << USB_OTG_DIEPTSIZ_XFRSIZ_Pos;
// Send 3 packets (8 bytes max for each)
in_endpoint->DIEPTSIZ |= 3 << USB_OTG_DIEPTSIZ_PKTCNT_Pos;
// Enable transmission
in_endpoint->DIEPCTL |= USB_OTG_DIEPCTL_CNAK;
in_endpoint->DIEPCTL |= USB_OTG_DIEPCTL_EPENA;
// Write a valid device descriptor to the Tx FIFO
*fifo = 0x02000112;
*fifo = 0x08000000;
*fifo = 0x13aa6666;
*fifo = 0x00000000;
*fifo = 0x0000012c;
fifo_space = in_endpoint->DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV_Msk;
printf("FIFO free space: %i\n", fifo_space);
}
Below is the log I'm getting from the device. I see that the first device request is transmitted successfully, the FIFO size drops from 16 to 11, than back to 16. Number of packets to send decreases from 3 to 2 (although it should decrease to 0, right?). I also see this descriptor with Wireshark. Then the device address is received and answered by a ZLP packet; then something goes wrong. My FIFO space keeps decreasing with every descriptor request, the packets doesn't seem to leave the device.
USB reset received
FIFO free space: 16
INEPNE Endpoint interrupt
TXFE Endpoint interrupt
// First descriptor request. Sent successfully
Received packet of status 0x06
// Device descriptor request in binary form
Rx from FIFO: 0x01000680
Rx from FIFO: 0x00400000
// Output from handle_descriptor_request()
Received descriptor request
Manual PKTCNT to 3
FIFO free space: 11
// Output from main()
Packets number update: 2
FIFO free space: 16
// Output from rxflvl_handler()
Received packet of status 0x04
Received packet of status 0x02
Received packet of status 0x03
INEPNE Endpoint interrupt
TXFE Endpoint interrupt
// Received address
Received packet of status 0x06
// Set address request in binary form
Rx from FIFO: 0x001d0500
Rx from FIFO: 0x00000000
Received address: 29
Writing zero-length packet
Manual PKTCNT to 1
Packets number update: 1
Received packet of status 0x04
Packets number update: 0
TXFRC Endpoint interrupt
TXFE Endpoint interrupt
// Another device descriptor request
Received packet of status 0x06
Rx from FIFO: 0x01000680
Rx from FIFO: 0x00120000
Received descriptor request
Manual PKTCNT to 3
FIFO free space: 11
Packets number update: 3
Received packet of status 0x04
// Looks unsuccessful. Try again...
Received packet of status 0x06
Rx from FIFO: 0x01000680
Rx from FIFO: 0x00120000
Received descriptor request
Manual PKTCNT to 3
FIFO free space: 6
// And so on. The FIFO free space decreases to 0
Here are the Wireshark views of the first and second descriptor responses. The second one fails with EOVERFLOW (-75). Sometimes I see -71 error when run 'dmesg' on my host. Can't figure out what is the reason for that.
If I will be flushing the 0th FIFO before the descriptor transmission, i.e. uncomment the
flush_txfifo(0);
Thing doesn't change a lot: the FIFO free space stops decreasing below 11, but the packets doesn't seem to be sent.
If I recover the endpoint before the descriptor tranmission, uncommenting the
in_endpoint->DIEPTSIZ = 0;
in_endpoint->DIEPCTL |= USB_OTG_DIEPCTL_SNAK;
in_endpoint->DIEPCTL |= USB_OTG_DIEPCTL_EPDIS;
then starting at the second try, the device seems to strart sending something, but still something wrong. The FIFO size increases to 15 words instead of 16
// ...
Rx from FIFO: 0x01000680
Rx from FIFO: 0x00120000
Received descriptor request
Manual PKTCNT to 3
FIFO free space: 11
FIFO free space: 15
Received packet of status 0x04
Received packet of status 0x02
Received packet of status 0x03
Also I can't understand why the number of packets drops from 3 to 2 for the successful transmission. I can see in Wireshark whole descriptor (18 bytes) and the endpoint size is configured to 8.
Could you point me to things I may need to check?
I want to send a command to my scooter via polidea ble but I don't know how to compose the package and encode it to base64, I tried different ways but it seems it does not work. Here is the documentation of how I need to make the package:
APP 🡪 Bluetooth
START_PACK, OPCODESEND, LENGTH, D0, CHECKSUM (START_PACK = 0x55)
OPCODESEND
0x02 – Speed Limit
D0 – 1 is 6Km/k, 2 is 12Km/h, 3 is 20Km/h, 4 is 25Km/h, 5 No speed Limit
0x03 - Change Zero Start
D0 🡪 0 Zero Start OFF, 1 Zero Start ON
0x05 –Lock Unlock Scooter
D0 🡪 0 Unlock, 1 Lock
0x06 – On/Off light from display
D0 🡪 0 light OFF, 1 light ON
For example, how should the package look to turn on the light?
My understanding of the documentation you have included, is that to turn on the light the code to create the packet in base64 would be:
import { Buffer } from "buffer";
var start_pack = 0x55;
var opcode = 0x06 // light
var action = 0x01 // On
var length = 0x01 // Length of what? action?
var checksum = start_pack + opcode + action + length
var valueBytes = Buffer.alloc(5);
valueBytes[0] = start_pack;
valueBytes[1] = opcode;
valueBytes[2] = length;
valueBytes[3] = action;
valueBytes[4] = checksum;
var valueBase64 = valueBytes.toString('base64')
console.log("Data to write: " + valueBase64)
This gave me an output of:
Data to write: VQYBAV0=
I know the default setting value for 'VIRTUAL_COM_PORT_DATA_SIZE 64' at usb_desc.h for STM32 Library.
however, I want to get the 255 bytes at one time due to the long packets of our project.
So I have changed the following modify code point, I couldn't get the right value with problem for 'USB defect problem'.
/****** usb_prop.c **********/
DEVICE_PROP Device_Property = {
Virtual_Com_Port_init,
Virtual_Com_Port_Reset,
Virtual_Com_Port_Status_In,
Virtual_Com_Port_Status_Out,
Virtual_Com_Port_Data_Setup,
Virtual_Com_Port_NoData_Setup,
Virtual_Com_Port_Get_Interface_Setting,
Virtual_Com_Port_GetDeviceDescriptor,
Virtual_Com_Port_GetConfigDescriptor,
Virtual_Com_Port_GetStringDescriptor,
0,
0xFF /*MAX PACKET SIZE*/ // default : 0x40
};
/****** usb_desc.c **********/
/* USB Standard Device Descriptor */
const uint8_t Virtual_Com_Port_DeviceDescriptor[] = {
0x12, /* bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
0x00,
0x02, /* bcdUSB = 2.00 */
0x02, /* bDeviceClass: CDC */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0xFF, /* bMaxPacketSize0 */ // default : 0x40
0x83,
0x04, /* idVendor = 0x0483 */
0x40,
0x57, /* idProduct = 0x7540 */
0x00,
0x02, /* bcdDevice = 2.00 */
1, /* Index of string descriptor describing manufacturer */
2, /* Index of string descriptor describing product */
3, /* Index of string descriptor describing the device's serial number */
0x01 /* bNumConfigurations */ };
/****** usb_desc.h **********/
#define VIRTUAL_COM_PORT_DATA_SIZE 255 // 0xFF, default : 64
please tell me how to modify in order to send as 255 bytes from USB packets.
You can't do it this way. The size of the packet is USB endpoint related and for the FS USB it is always 64 bytes. My advice is: do not modify any descriptors unless you really know what are you doing (which is not the case here).
How to receive larger chunks of data:
create a buffer
when data arrives copy it (append) to that buffer
check if you have received all data needed
if not go to point (2) else goto point(5)
Do something with the data (your large packet)
Reset the buffer and goto point 2
I want to transfer 256 bytes from host to stm32f103 device over USB Custom HID interface
Currently, 64 bytes Read/Write is Working
Following is the Report Descriptor in my stm32:
/** Usb HID report descriptor. */
static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END ={
0x06,0x00,0xFF, //Usage Page 0xff00
0x09, 0x01, //USAGE (Pointer)
0xA1,0x01, //Collection (application)
//Input Report
0x19,0x01, //Usage Minimum
0x29,0x40, //Usage Minimum
0x15,0x00, //Logical Minimum
0x26,0xFF,0x00, //Logical Minimum
0x75,0x08, //report size : 8-bit field size
0x95, CUSTOM_HID_EPIN_SIZE,//Report count
0x81,0x02, //Input (data, array, Abs)
//Output Report
0x19,0x01, //usage Minimum
0x29,0x40, //usage Minimum
0x75,0x08, //report size : 8-bit field size
0x95,CUSTOM_HID_EPOUT_SIZE,//Report Count
0x91,0x02, //Output (data, array, Abs)
0xC0 //END_COLLECTION
};
If, I am changing the CUSTOM_HID_EPIN_SIZE,CUSTOM_HID_EPOUT_SIZE to 256, my USB device is not recognized.
I need some help to modify the report descriptor to support 256 byte transfer
Thanks
I'm trying to get a basic handshake going. Below is the ISR for the C8051F120's SMBus (System Management Bus). I'm trying to implement an I2C device on it (ads1115 7addr 0x48 for those who are curious). Note this is mainly the example given by silicon labs for the F120.
void SMBUS_ISR (void) interrupt 7
{
bit FAIL = 0; // Used by the ISR to flag failed
// transfers
static unsigned char sent_byte_counter;
static unsigned char rec_byte_counter;
// Status code for the SMBus (SMB0STA register)
switch (SMB0STA)
{
// Master Transmitter/Receiver: START condition transmitted.
// Load SMB0DAT with slave device address.
case SMB_START: //0x08
// Master Transmitter/Receiver: repeated START condition transmitted.
// Load SMB0DAT with slave device address
case SMB_RP_START: //0x10
SMB0DAT = TARGET; // Load address of the slave.
SMB0DAT &= 0xFE; // Clear the LSB of the address for the
// R/W bit
SMB0DAT |= SMB_RW; // Load R/W bit
STA = 0; // Manually clear STA bit
rec_byte_counter = 1; // Reset the counter
sent_byte_counter = 1; // Reset the counter
break;
// Master Transmitter: Slave address + WRITE transmitted. ACK received.
// For a READ: N/A
//
// For a WRITE: Send the first data byte to the slave.
case SMB_MTADDACK: //0x18
SMB0DAT = SMB_DATA_OUT[sent_byte_counter-1];
sent_byte_counter++;
break;
// Master Transmitter: Slave address + WRITE transmitted. NACK received.
// Restart the transfer.
case SMB_MTADDNACK: //0x20
STA = 1; // Restart transfer
break;
// Master Transmitter: Data byte transmitted. ACK received.
// For a READ: N/A
//
// For a WRITE: Send all data. After the last data byte, send the stop
// bit.
case SMB_MTDBACK: //0x28
if (sent_byte_counter <= NUM_BYTES_WR)
{
// send data byte
SMB0DAT = SMB_DATA_OUT[sent_byte_counter-1];
sent_byte_counter++;
}
else
{
STO = 1; // Set STO to terminate transfer
SMB_BUSY = 0; // And free SMBus interface
}
break;
// Master Transmitter: Data byte transmitted. NACK received.
// Restart the transfer.
case SMB_MTDBNACK: //0x30
STA = 1; // Restart transfer
break;
// Master Receiver: Slave address + READ transmitted. ACK received.
// For a READ: check if this is a one-byte transfer. if so, set the
// NACK after the data byte is received to end the transfer. if not,
// set the ACK and receive the other data bytes.
//
// For a WRITE: N/A
case SMB_MRADDACK: //0x40
if (rec_byte_counter == NUM_BYTES_RD)
{
AA = 0; // Only one byte in this transfer,
// send NACK after byte is received
}
else
{
AA = 1; // More than one byte in this transfer,
// send ACK after byte is received
}
break;
// Master Receiver: Slave address + READ transmitted. NACK received.
// Restart the transfer.
case SMB_MRADDNACK: //0x48
STA = 1; // Restart transfer
break;
// Master Receiver: Data byte received. ACK transmitted.
// For a READ: receive each byte from the slave. if this is the last
// byte, send a NACK and set the STOP bit.
//
// For a WRITE: N/A
case SMB_MRDBACK: //0x50
if (rec_byte_counter < NUM_BYTES_RD)
{
SMB_DATA_IN[rec_byte_counter-1] = SMB0DAT; // Store received byte
AA = 1; // Send ACK to indicate byte received
rec_byte_counter++; // Increment the byte counter
}
else
{
AA = 0; // Send NACK to indicate last byte
// of this transfer
}
break;
// Master Receiver: Data byte received. NACK transmitted.
// For a READ: Read operation has completed. Read data register and
// send STOP.
//
// For a WRITE: N/A
case SMB_MRDBNACK: //0x58
SMB_DATA_IN[rec_byte_counter-1] = SMB0DAT; // Store received byte
STO = 1;
SMB_BUSY = 0;
AA = 1; // Set AA for next transfer
break;
// Master Transmitter: Arbitration lost.
case SMB_MTARBLOST: //0x38
FAIL = 1; // Indicate failed transfer
// and handle at end of ISR
break;
// All other status codes invalid. Reset communication.
default:
FAIL = 1;
break;
}
if (FAIL) // If the transfer failed,
{
SMB0CN &= ~0x40; // Reset communication
SMB0CN |= 0x40;
STA = 0;
STO = 0;
AA = 0;
SMB_BUSY = 0; // Free SMBus
FAIL = 0;
}
SI = 0; // Clear interrupt flag
}
//-----------------------------------------------------------------------------
// Support Functions
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// SMB_Write
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Writes a single byte to the slave with address specified by the <TARGET>
// variable.
// Calling sequence:
// 1) Write target slave address to the <TARGET> variable
// 2) Write outgoing data to the <SMB_DATA_OUT> array
// 3) Call SMB_Write()
//
void SMB_Write (void)
{
char SFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
SFRPAGE = SMB0_PAGE;
while (SMB_BUSY); // Wait for SMBus to be free.
SMB_BUSY = 1; // Claim SMBus (set to busy)
SMB_RW = 0; // Mark this transfer as a WRITE
STA = 1; // Start transfer
SFRPAGE = SFRPAGE_SAVE; // Restore SFR page detector
}
//-----------------------------------------------------------------------------
// SMB_Read
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Reads a single byte from the slave with address specified by the <TARGET>
// variable.
// Calling sequence:
// 1) Write target slave address to the <TARGET> variable
// 2) Call SMB_Write()
// 3) Read input data from <SMB_DATA_IN> array
//
void SMB_Read (void)
{
char SFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
SFRPAGE = SMB0_PAGE;
while (SMB_BUSY); // Wait for bus to be free.
SMB_BUSY = 1; // Claim SMBus (set to busy)
SMB_RW = 1; // Mark this transfer as a READ
STA = 1; // Start transfer
while (SMB_BUSY); // Wait for transfer to complete
SFRPAGE = SFRPAGE_SAVE; // Restore SFR page detector
}
The main continuously does the following: Sends 3 bytes. The first byte is the device register pointer. Then reads the same register (since the pointer is already set). It does do this.
while (1)
{
TARGET = SLAVE_ADDR; // Target the Slave for next SMBus
// transfer
SMB_DATA_OUT[0] = 0x01; // Device register
SMB_DATA_OUT[1] = 0x0A; // Register MSByte
SMB_DATA_OUT[2] = 0x03; // Register LSbyte
SMB_Write(); // Initiate SMBus write
// SMBus Read Sequence
TARGET = SLAVE_ADDR; // Target the Slave for next SMBus
// transfer
SMB_Read();
}
And here is a trace capture of transfer:
Looks to me like the master receive is sending an extra ACK. So my main focus has been on cases:
SMB_MRADDACK: //0x40
SMB_MRADDNACK: //0x48
SMB_MRDBACK: //0x50
My main focus is more so SMB_MRADDNACK: //0x48 and the number of times it goes through that if statement during the ISR calls. I'm having a little trouble wrapping my head around the exact failure point. So where is this extra ACK coming from? I'll look back here Monday afternoon if I don't figure it out myself by then.
Bonus question: Is there a embedded stack exchange of some sort? Didn't see anything that stood out for me in the communities..
Your trace shows (excluding addressing) three bytes sent and three bytes read. I'm assuming you desired to write three bytes and then only read two bytes. If that's true, then the problem is more than just a spurious ACK because your master continues clocking the third byte in as well.
If you desire to read only two bytes with the sample code from SiLabs1, you need to define NUM_BYTES_RD to 2 instead of the provided 3. That value is used in the SMB_MRADDACK and SMB_MRDBACK states to decide whether to ACK or STOp.
Just in case (since you ask about ACKs instead of extra bytes), if your question is about the final drop in the SDL line on your trace (after the 0xff) because you're afraid that's an extra ACK, then worry not. That is a STO (rises during high SCL) and is correct behavior for a Master terminating a transmission.
Edit: klamb is correct in the comments below below, there is bug in the SMB_MRDBACK state. Saving SMB0DAT and incrementing rec_byte_counter should happen before checking rec_byte_counter against NUM_BYTES_RD. Suprising that got out of SiLabs like that.
case SMB_MRDBACK: //0x50
SMB_DATA_IN[rec_byte_counter-1] = SMB0DAT; // Store received byte
rec_byte_counter++; // Increment the byte counter
if (rec_byte_counter < NUM_BYTES_RD)
{
AA = 1; // Send ACK to indicate byte received
}
else
{
AA = 0; // Send NACK to indicate last byte
// of this transfer
}
break;