I'm developing code for the NXP LPC1788 microcontroller, and part of my work is making the product based on it USB-compatible. Most of the legwork is done and in general communication over USB works almost as well as over CAN.
However, one of the issues I've been encountering is that, when producing a constant output of USB messages from the microcontroller that are sent pretty close together, some of these messages are occasionally dropped.
I'm using a custom driver I wrote based on WinUSB to receive the messages on the PC side, and I originally suspected that the problem was on the receiving end of things. However, using USBLyzer I'm now confident that the problem is on the sending side - the USBLyzer logs perfectly match logs produced from what I get out of WinUsb_ReadPipe().
The LPC1788 uses USB 2.0 Full Speed protocol and I've confirmed that information is being sent and received at around 12 MHz using a probe, which is what it should be.
The device is configured to make use of two endpoints: logical endpoint 2 IN and logical endpoint 2 OUT. Both of these are configured for bulk transfer with a maximum packet size of 64 bytes.
I would think that messages are being sent around 500-600 microseconds apart at the least (I've introduced an artificial 500 us delay in the thread and message transmission should take a lot less time than that). This is about what I got last week; I can't check now as my debugging tools are acting up.
This is the USB initialisation code for the microcontroller:
void USBInit()
{
// Configure USB pins.
PINSEL_ConfigPin(0, 29, 1); // USB_D+1
PINSEL_ConfigPin(0, 30, 1); // USB_D-1
PINSEL_ConfigPin(1, 18, 1); // USB_UP_LED1
PINSEL_ConfigPin(2, 9, 1); // USB_CONNECT1
PINSEL_ConfigPin(1, 30, 2); // USB_VBUS
// Turn on power and clock
CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCUSB, ENABLE);
PINSEL_SetPinMode(1, 30, PINSEL_BASICMODE_PLAINOUT);
// Set DEV_CLK_EN and AHB_CLK_EN.
LPC_USB->USBClkCtrl |= 0x12;
// Wait until change is reflected in clock status register.
while((LPC_USB->USBClkSt & 0x12) != 0x12);
// Enable NVIC USB interrupts.
NVIC_EnableIRQ(USB_IRQn);
// Reset the USB.
USBReset();
// Set device address to 0x0 and enable device & connection.
USBSetAddress(0);
}
This is the code used by the microcontroller to send messages via USB:
uint32_t USB_Send(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
// Convert into a form that can be sent successfully using USB.
uint8_t data[USB_MAX_PACKET_SIZE];
for(int i=0; i < count; i++)
{
data[i*2] = hex[(pData[i] >> 4)];
data[(i*2)+1] = hex[(pData[i] & 0xF)];
}
return USBWriteEndpoint(endpoint, data, count*2);
}
uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
uint32_t i;
LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;
LPC_USB->TxPLen = count;
for(i=0; i < (count+3)/4; i++)
{
LPC_USB->TxData = *((__packed uint32_t *)pData);
pData += 4;
}
LPC_USB->Ctrl = 0;
USBValidateEndpoint(endpoint);
return count;
}
void USBValidateEndpoint(uint32_t endpoint)
{
writeSIEEndpointCommand(endpoint, CMD_VALID_BUF);
}
void writeSIECommandData(uint32_t cmd, uint32_t data)
{
LPC_USB->DevIntClr = CCEMTY_INT;
LPC_USB->CmdCode = cmd;
while((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
LPC_USB->DevIntClr = CCEMTY_INT;
LPC_USB->CmdCode = data;
while((LPC_USB->DevIntSt & CCEMTY_INT) == 0);
}
EDIT
To give an idea of what's happening, this is a log file produced from my USB driver's receive function (the one from USBLyzer is practically identical):
0000030D000D
0000010D002D0004001B0024
0000000D0FFF001600310016
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000000D0FFF001600310016
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000000D0FFF001600310016
0000010D002D0004001F0028
0000020D00280028001B002D
0000030D0009
0000010D002D0004001F0028
I should be receiving messages in the following cycle:
0000000D...
0000010D...
0000020D...
0000030D...
You can see from this log that some of the messages in the cycle are getting skipped.
EDIT 2
Included below are excerpts from the raw and filtered capture logs produced by USBLyzer. The raw logs mostly consist of cancelled requests because my driver is poll-driven and uses a timeout.
Raw logs:
USBlyzer Report
Capture List
Type Seq Time Elapsed Duration Request Request Details Raw Data I/O C:I:E Device Object Device Name Driver Name IRP Status
START 0001 11:09:15.413
URB 0002 11:09:18.484 3.071197 s Bulk or Interrupt Transfer 10 bytes data 30 30 30 30 30 30 31 46... out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA801142FAB0h
00000000 30 30 30 30 30 30 31 46 30 31 0000001F01
URB 0003 11:09:18.484 3.071212 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0004-0002 11:09:18.484 3.071371 s 174 us Bulk or Interrupt Transfer 10 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA801142FAB0h Success (Success)
URB 0005-0003 11:09:18.485 3.071586 s 374 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
URB 0006 11:09:18.485 3.071608 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0007-0006 11:09:18.486 3.072582 s 974 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
URB 0008 11:09:18.486 3.072603 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0009-0008 11:09:18.487 3.073598 s 996 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
URB 0010 11:09:18.487 3.073630 s Bulk or Interrupt Transfer 64 bytes buffer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h
URB 0011-0010 11:09:18.488 3.074601 s 970 us Bulk or Interrupt Transfer in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Cancelled (Canceled)
[...]
URB 2504-2501 11:09:19.734 4.320666 s 161 us Bulk or Interrupt Transfer 14 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA800CF662D0h Success (Success)
URB 2505-2503 11:09:19.734 4.320785 s 192 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 30 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36 0000000D0FFF0016
00000010 30 30 33 31 30 30 31 42 0031001B
Filtered logs:
USBlyzer Report
Capture List
Type Seq Time Elapsed Duration Request Request Details Raw Data I/O C:I:E Device Object Device Name Driver Name IRP Status
URB 0004-0002 11:09:18.484 3.071371 s 174 us Bulk or Interrupt Transfer 10 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA801142FAB0h Success (Success)
URB 2504-2501 11:09:19.734 4.320666 s 161 us Bulk or Interrupt Transfer 14 bytes buffer out 01:00:02 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA800CF662D0h Success (Success)
URB 2505-2503 11:09:19.734 4.320785 s 192 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 30 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36 0000000D0FFF0016
00000010 30 30 33 31 30 30 31 42 0031001B
URB 2507-2506 11:09:19.734 4.321309 s 459 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 31 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 31 30 44 30 30 32 44 30 30 30 34 0000010D002D0004
00000010 30 30 31 46 30 30 32 44 001F002D
URB 2511-2510 11:09:19.735 4.321931 s 311 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 32 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 32 30 44 30 30 32 38 30 30 32 38 0000020D00280028
00000010 30 30 31 42 30 30 33 31 001B0031
URB 2513-2512 11:09:19.735 4.322306 s 332 us Bulk or Interrupt Transfer 12 bytes data 30 30 30 30 30 33 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 33 30 44 30 30 30 44 0000030D000D
URB 2725-2724 11:09:19.840 4.426662 s 89 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 30 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 30 30 44 30 46 46 46 30 30 31 36 0000000D0FFF0016
00000010 30 30 33 31 30 30 31 42 0031001B
URB 2727-2726 11:09:19.840 4.427183 s 471 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 31 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 31 30 44 30 30 32 44 30 30 30 34 0000010D002D0004
00000010 30 30 31 46 30 30 32 44 001F002D
URB 2731-2730 11:09:19.841 4.427803 s 209 us Bulk or Interrupt Transfer 24 bytes data 30 30 30 30 30 32 30 44... in 01:00:82 FFFFFA800FC98440h USBPDO-11 usbhub FFFFFA8010E965A0h Success (Success)
00000000 30 30 30 30 30 32 30 44 30 30 32 38 30 30 32 38 0000020D00280028
00000010 30 30 31 42 30 30 33 31 001B0031
Do you have a hardware USB analyzer available? I'm not sure how USBLyzer works but I presume it is still using the Windows USB subsystem at the lowest levels. My experience with Windows USB subsystem has been that it is extremely bug-riddled - one particular example was when transferring data that is an exact multiple of the max frame size, it doesn't work. I'm not saying this is your exact problem - we had different symptoms from what you are reporting - but in your shoes I would look at a) changing the max amount of data your transmitting end will send in one frame so it's not an exact multiple of the frame size, and b) getting a hardware USB analyzer to see what is actually on the wire.
The problem might be the USB_IRQHandler interrupting your write function. That would leave the USB unexpected in a different state, thus the write fails.
You can temporary disable the IRQ as a workaround:
uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
uint32_t i;
NVIC_DisableIRQ(USB_IRQn); // USB IRQ handlaer must not run ...
LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;
LPC_USB->TxPLen = count;
for(i=0; i < (count+3)/4; i++)
{
LPC_USB->TxData = *((__packed uint32_t *)pData);
pData += 4;
}
LPC_USB->Ctrl = 0;
USBValidateEndpoint(endpoint);
NVIC_EnableIRQ(USB_IRQn); // ... until we are here. Enable USB IRQ again
return count;
}
I think I've managed to make some significant improvements in the way that the microcontroller sends USB messages.
On page 400 of the LPC178x/7x user manual, I saw a description for how to properly handle sending data from the device to the host using a bulk IN endpoint. It was pretty lucky that I eventually stumbled across it since it was within the DMA section of the chapter (and I'm not using DMA so until now I've ignored it).
Based on what I read there, I added the following method:
// Params: endpoint - the logical endpoint number.
// Returns: TRUE if at least one write buffer is free,
// FALSE otherwise.
// Description: Checks that the IN endpoint has a free write buffer.
uint8_t USBCheckInEndpointFree(uint32_t endpoint)
{
uint16_t data;
uint32_t physicalEndpoint = getEndpointPhysicalAddress(endpoint);
writeSIECommand(CMD_SEL_EP(physicalEndpoint));
data = readSIECommandData(DAT_SEL_EP(physicalEndpoint));
return (data & 0x1) == 0;
}
I changed USBWriteEndpoint to the following:
uint32_t USBWriteEndpoint(uint32_t endpoint, uint8_t *pData, uint32_t count)
{
uint32_t i = 0;
NVIC_DisableIRQ(USB_IRQn);
if((endpoint & 0xF) != 0)
{
while(getSendMessageFlag(endpoint & 0xF) != 0);
setSendMessageFlag(endpoint & 0xF);
}
while(!USBCheckInEndpointFree(endpoint))
{
uint32_t physicalEndpoint = getEndpointPhysicalAddress(endpoint);
writeSIECommand(CMD_SEL_EP(physicalEndpoint));
ITM_EVENT32_WITH_PC(3, readSIECommandData(DAT_SEL_EP(physicalEndpoint)));
}
LPC_USB->Ctrl = ((endpoint & 0xF) << 2) | CTRL_WR_EN;
LPC_USB->TxPLen = count;
for(i=0; i < (count+3)/4; i++)
{
LPC_USB->TxData = *((__packed uint32_t *)(pData+i*4));
//pData += 4;
}
ITM_EVENT32_WITH_PC(4, (pData[4] << 24) | (pData[5] << 16) | (pData[6] << 8) | pData[7]);
LPC_USB->Ctrl = 0;
USBValidateEndpoint(endpoint);
NVIC_EnableIRQ(USB_IRQn);
return count;
}
The ITM_EVENT32_WITH_PC macro is used for debugging.
While sending USB messages at a high rate, I noticed this pattern in the event timeline:
In that image, the lines within the third channel show where the thread is caught within the while loop because none of the write buffers of the endpoint I'm using are free. The lines in the fourth channel are where a message is written to one of the endpoint's write buffers.
The LPC1788 uses double-buffering for bulk and isochronous endpoints, so what you're seeing in that image is the following:
The microcontroller tries to send a USB message to the host. Both write buffers are free, so it picks one and uses that.
The micro tries to send a second message. It uses the remaining free write buffer.
The micro tries to send a third message. Both buffers are in use so it has to wait. That produces the series of lines in the third channel while the micro polls the endpoint status.
Eventually one of the buffers (probably the first one used) becomes free, and the message is written to that.
The micro tries to send a fourth message. Both buffers are in use and the micro apparently has to wait a fair while before one of them becomes free.
Eventually one of the buffers becomes free and it writes the message to that.
Before adding in that additional check, I got behaviour like this:
Clearly without the check, the endpoint's buffers are getting overwritten!
To check how well this change resolved the problem, I created a Python script with a simple algorithm that I chose to evaluate performance by comparing how well the output from the USB logs (generated by one of my USB drivers on the PC end) conforms to a perfect cycle (which is what I'd ideally want).
I did three runs of my program with the additional check and three runs of my program without it, each time leaving it running long enough for 1000 USB messages to be received and recorded in a log file by the DLL.
The three logs with the additional check were USBLogGood1.txt ... USBLogGood3.txt. The three without the check were USBLogBad1.txt ... USBLogBad3.txt.
The Python code is given below:
# Checks how well the USB is performing by checking how
# closely the stream of USB messages returned by the DLL
# matches a perfect cyclical pattern.
from statistics import *
cycle = [1,2,3,4]
sampleSize = 1000
class Globals:
totalCount = 0
errorCount = 0
usbLogFile = "usbLog.txt"
usbGoodLogFiles = ["usbLogGood1.txt",
"usbLogGood2.txt",
"usbLogGood3.txt"]
usbBadLogFiles = ["usbLogBad1.txt",
"usbLogBad2.txt",
"usbLogBad3.txt"]
# Switch between sets of log files.
usbLogFiles = usbBadLogFiles
# Read log file.
def readLog(logFile):
with open(logFile) as fIn:
return fIn.readlines()
# Converts raw log data into a list of cycle values.
def processLog(log):
data = []
for line in log:
data.append(processLogLine(line))
return data
# Converts raw log line into a cycle value.
def processLogLine(logLine):
l = logLine.replace("Message ", "")
return int(l[5],16)+1
# Counts distance in one direction, so the distance
# will be high if i2 is behind i1.
def getListDistance(val1, val2):
cycleLen = len(cycle)
i1 = cycle.index(val1)
i2 = cycle.index(val2)
if i1 <= i2:
return i2 - i1
else:
return (cycleLen - i1) + i2
def getNextValueInCycle(val):
cycleLen = len(cycle)
i = cycle.index(val)
if i < cycleLen-1:
return cycle[i+1]
else:
return cycle[0]
def checkCycleValue(expected, value):
Globals.totalCount += 1
if value != expected:
Globals.errorCount += getListDistance(expected, value)
expected = getNextValueInCycle(value)
return expected
def getPerformance():
return 1-float(Globals.errorCount)/float(Globals.totalCount)
def printPerformance():
print("Sampled %d values. USB performance: %0.1f%%"
% (Globals.totalCount, getPerformance()*100))
# Read log file and evaluate performance.
def evaluatePerformance(logFile):
Globals.totalCount = 0
Globals.errorCount = 0
log = readLog(logFile)
data = processLog(log)
if not data:
print("No data available")
return
if len(data) < sampleSize:
print("Not enough data available to meet requirements")
return
else:
data = data[:sampleSize]
expected = data[0]
for value in data:
expected = checkCycleValue(expected, value)
return getPerformance()
def printAggregatePerformanceData(logFiles, performances):
performances = [100*p for p in performances]
for f, p in zip(logFiles, performances):
print("%s: %0.2f%%" % (f, p))
print("\nAverage performance: %0.2f%%" % mean(performances))
print("Standard deviation: %0.2f" % stdev(performances))
def main():
performances = []
for logFile in usbLogFiles:
performances.append(evaluatePerformance(logFile))
printAggregatePerformanceData(usbLogFiles, performances)
if __name__ == "__main__":
main()
With the good set of logs, I got the following output:
usbLogGood1.txt: 93.70%
usbLogGood2.txt: 92.50%
usbLogGood3.txt: 92.60%
Average performance: 92.93%
Standard deviation: 0.67
For the bad set, I got this:
usbLogBad1.txt: 16.60%
usbLogBad2.txt: 13.80%
usbLogBad3.txt: 14.10%
Average performance: 14.83%
Standard deviation: 1.54
By adding in the additional check to make sure a write buffer is free, I managed to increase the 'performance' of the USB by around 78.1% (100% means a perfect cycle of USB messages: 1,2,3,4,1,2,3,4,1,2,3,4...).
In addition to this, I found that the message throughput about doubled when I put the check in, despite the delays associated with waiting in while loops.
92.93% still isn't perfect, but the manual talks about checking for ACKS from the host as well as just free write endpoints. I tried to do that earlier (without apparent success), but this was before I tried this check. Hopefully, if I implement both together I can get the USB performance to rival that of CAN.
Edit: The wait for ACK thing didn't work, but if I force a 1ms delay in between sending messages, I can get a performance of ~99.99...%.
This is not an ideal solution since 1ms is quite a long time to be delaying for, so I'm leaving the question unresolved for now.
EDIT
I quite firmly believe at this point that the issue is mainly with the PC-side driver I wrote. It doesn't read fast enough.
Related
I'm trying to replicate a Windows program on Linux. The program talks to the USB device.
Now I'm stuck on the part where the device sends URB_interrupt IN first, and the host answers. The capture looks like this (and this is the result I want to have):
Frame 29: 72 bytes on wire (576 bits), 72 bytes captured (576 bits) on interface usbmon0, id 0
USB URB
[Source: 1.16.2]
[Destination: host]
URB id: 0xffff8d92d4ece840
URB type: URB_COMPLETE ('C')
URB transfer type: URB_INTERRUPT (0x01)
Endpoint: 0x82, Direction: IN
Device: 16
URB bus id: 1
Device setup request: not relevant ('-')
Data: present (0)
URB sec: 1664781571
URB usec: 862138
URB status: Success (0)
URB length [bytes]: 8
Data length [bytes]: 8
[bInterfaceClass: Unknown (0xffff)]
Unused Setup Header
Interval: 8
Start frame: 0
Copy of Transfer Flags: 0x00000200, Dir IN
Number of ISO descriptors: 0
Leftover Capture Data: 0508ff0000000000
Frame 30: 64 bytes on wire (512 bits), 64 bytes captured (512 bits) on interface usbmon0, id 0
USB URB
[Source: host]
[Destination: 1.16.2]
URB id: 0xffff8d9321011cc0
URB type: URB_SUBMIT ('S')
URB transfer type: URB_INTERRUPT (0x01)
Endpoint: 0x82, Direction: IN
Device: 16
URB bus id: 1
Device setup request: not relevant ('-')
Data: not present ('<')
URB sec: 1664781571
URB usec: 865989
URB status: Operation now in progress (-EINPROGRESS) (-115)
URB length [bytes]: 8
Data length [bytes]: 0
[bInterfaceClass: Unknown (0xffff)]
Unused Setup Header
Interval: 8
Start frame: 0
Copy of Transfer Flags: 0x00000200, Dir IN
Number of ISO descriptors: 0
It looks like the device sends the answer first (URB type is 'URB_COMPLETE'), and after that, the host answers ('URB_SUBMIT'). Previously I have only encountered the opposite situation (i. e. swap order of the captured packets) and I know how to do it, but I have no idea how to do the upper-mentioned one.
I do the URB interrupt by the following function:
#define INTR_EP_IN 0x82
#define INTR_LENGTH 8
typedef unsigned char byte_t;
/* Proper opening, kernel detaching, and interface claiming... */
static int send_interrupt(libusb_device_handle *handle)
{
byte_t *packet;
int transferred = 0;
short sent;
packet = calloc(INTR_LENGTH, 1);
sent = libusb_interrupt_transfer(handle, INTR_EP_IN, packet, INTR_LENGTH,
&transferred, 10);
free(packet);
/* Note: always TIMEOUT_ERROR, but the packet gets captured anyway */
/*
if(sent != 0)
fprintf(stderr, INTRRPT_ERR_MSG, libusb_strerror(sent));
*/
return sent;
}
I've tried to change libusb_interrupt_transfer parameters, but nothing gave me the desired result.
Every time I get something like the following:
Frame 30: 64 bytes on wire (512 bits), 64 bytes captured (512 bits) on interface usbmon0, id 0
USB URB
[Source: host]
[Destination: 1.6.2]
URB id: 0xffff922c3bd69540
URB type: URB_SUBMIT ('S')
URB transfer type: URB_INTERRUPT (0x01)
Endpoint: 0x82, Direction: IN
Device: 6
URB bus id: 1
Device setup request: not relevant ('-')
Data: not present ('<')
URB sec: 1668092600
URB usec: 503008
URB status: Operation now in progress (-EINPROGRESS) (-115)
URB length [bytes]: 8
Data length [bytes]: 0
[Response in: 31]
[bInterfaceClass: Unknown (0xffff)]
Unused Setup Header
Interval: 8
Start frame: 0
Copy of Transfer Flags: 0x00000200, Dir IN
Number of ISO descriptors: 0
Frame 31: 64 bytes on wire (512 bits), 64 bytes captured (512 bits) on interface usbmon0, id 0
USB URB
[Source: 1.6.2]
[Destination: host]
URB id: 0xffff922c3bd69540
URB type: URB_COMPLETE ('C')
URB transfer type: URB_INTERRUPT (0x01)
Endpoint: 0x82, Direction: IN
Device: 6
URB bus id: 1
Device setup request: not relevant ('-')
Data: present (0)
URB sec: 1668092600
URB usec: 506108
URB status: No such file or directory (-ENOENT) (-2)
URB length [bytes]: 0
Data length [bytes]: 0
[Request in: 30]
[Time from request: 0.003100000 seconds]
[bInterfaceClass: Unknown (0xffff)]
Unused Setup Header
Interval: 8
Start frame: 0
Copy of Transfer Flags: 0x00000200, Dir IN
Number of ISO descriptors: 0
Which totally isn't what I intend to have.
I'm assuming I don't know something as I am not an expert in the USB protocol. There's also a chance that libusb just doesn't allow to do such transfer. In this case, I should do this via corresponding syscalls, but this is the last resort for me.
I started with ESP32 last week and currently I am trying to put together the example codes for the BLE iBeacon and a 1-sec-alarm timer. I receive the error abort() was called at PC 0x403774b7 on core 0 0x403774b7: lock_acquire_generic at /home/boko/esp/esp-idf/components/newlib/locks.c:130 when running the program. I have a single ESP_LOGI() statement within the timer callback timer_alarm_cb, which seems to cause the issue, but I don't know why and how (if I remove the statment, the program works fine). What I want to achieve with the code is to get a debug print every 1 second as a visual feedback in order to know how many and which iBeacons have been detected within a 1 sec interval.
So, my 2 questions are:
Why the ESP_LOGI() statement within the timer callback causes the program to abort ?
What is the otherwise correct way to get debug print every 1 sec using a timer in ESP32?
My code is:
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/****************************************************************************
*
* This file is for iBeacon demo. It supports both iBeacon sender and receiver
* which is distinguished by macros IBEACON_SENDER and IBEACON_RECEIVER,
*
* iBeacon is a trademark of Apple Inc. Before building devices which use iBeacon technology,
* visit https://developer.apple.com/ibeacon/ to obtain a license.
*
****************************************************************************/
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "nvs_flash.h"
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gattc_api.h"
#include "esp_gatt_defs.h"
#include "esp_bt_main.h"
#include "esp_bt_defs.h"
#include "esp_ibeacon_api.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h" // If you include FreeRTOS.h before task.h then portmacro.h will be included for you (do not include portmacro.h manually, just include FreeRTOS.h). However, if you fail to include FreeRTOS.h before tasks.h, then your code will not build
// #include "freertos/task.h" // BaseType_t
#include "driver/gptimer.h"
static const char* PROGRAM_NAME = "iBeacon2Omnicomm" ; // "iBeacons-ESP32-Tracker-Server" ; // "IBEACON_DEMO";
extern esp_ble_ibeacon_vendor_t vendor_config;
///Declare static functions
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
#if (IBEACON_MODE == IBEACON_RECEIVER)
static esp_ble_scan_params_t ble_scan_params = {
.scan_type = BLE_SCAN_TYPE_ACTIVE,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
.scan_interval = 0x50, // 50 ms scan interval, i.e. start scanning for BLE devices every 50 ms elapsed
.scan_window = 0x30, // 30 ms scan duration, i.e. whenever a scan interval starts, keep scanning for 30 ms
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
};
#elif (IBEACON_MODE == IBEACON_SENDER)
static esp_ble_adv_params_t ble_adv_params = {
.adv_int_min = 0x20,
.adv_int_max = 0x40,
.adv_type = ADV_TYPE_NONCONN_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
#endif
static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
esp_err_t err;
switch (event) {
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:{
#if (IBEACON_MODE == IBEACON_SENDER)
esp_ble_gap_start_advertising(&ble_adv_params);
#endif
break;
}
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {
#if (IBEACON_MODE == IBEACON_RECEIVER)
//the unit of the duration is second, 0 means scan permanently
uint32_t duration = 0;
ESP_LOGI(PROGRAM_NAME, "starting a scan == calling esp_ble_gap_start_scanning()");
esp_ble_gap_start_scanning(duration);
#endif
break;
}
case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
//scan start complete event to indicate scan start successfully or failed
if ((err = param->scan_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(PROGRAM_NAME, "Scan start failed: %s", esp_err_to_name(err));
} else {
ESP_LOGI(PROGRAM_NAME, "Scan start successful");
}
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
//adv start complete event to indicate adv start successfully or failed
if ((err = param->adv_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(PROGRAM_NAME, "Adv start failed: %s", esp_err_to_name(err));
}
break;
case ESP_GAP_BLE_SCAN_RESULT_EVT: {
esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param; // make a local copy of the passed address of parameters
switch (scan_result->scan_rst.search_evt) {
case ESP_GAP_SEARCH_INQ_RES_EVT:
/* Search for BLE iBeacon Packet */
if (esp_ble_is_ibeacon_packet(scan_result->scan_rst.ble_adv, scan_result->scan_rst.adv_data_len)){
esp_ble_ibeacon_t *ibeacon_data = (esp_ble_ibeacon_t*)(scan_result->scan_rst.ble_adv);
// ESP_LOGI("iBeacon Found:"); // error: macro "ESP_LOGI" requires 3 arguments, but only 1 given
ESP_LOGI(PROGRAM_NAME, "iBeacon Found ==========");
esp_log_buffer_hex("MAC address:", scan_result->scan_rst.bda, ESP_BD_ADDR_LEN );
esp_log_buffer_hex("UUID:", ibeacon_data->ibeacon_vendor.proximity_uuid, ESP_UUID_LEN_128);
uint16_t major = ENDIAN_CHANGE_U16(ibeacon_data->ibeacon_vendor.major);
uint16_t minor = ENDIAN_CHANGE_U16(ibeacon_data->ibeacon_vendor.minor);
ESP_LOGI(PROGRAM_NAME, "Major: 0x%04x (%d)", major, major);
ESP_LOGI(PROGRAM_NAME, "Minor: 0x%04x (%d)", minor, minor);
//ESP_LOGI(PROGRAM_NAME, "Measured power (RSSI at a 1m distance):%d dbm", ibeacon_data->ibeacon_vendor.measured_power);
ESP_LOGI(PROGRAM_NAME, "RSSI:%d dbm", scan_result->scan_rst.rssi);
}
break;
default:
break;
}
break;
}
case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
if ((err = param->scan_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS){
ESP_LOGE(PROGRAM_NAME, "Scan stop failed: %s", esp_err_to_name(err));
}
else {
ESP_LOGI(PROGRAM_NAME, "Stop scan successfully");
}
break;
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
if ((err = param->adv_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS){
ESP_LOGE(PROGRAM_NAME, "Adv stop failed: %s", esp_err_to_name(err));
}
else {
ESP_LOGI(PROGRAM_NAME, "Stop adv successfully");
}
break;
default:
break;
}
}
void ble_ibeacon_appRegister(void)
{
esp_err_t status;
ESP_LOGI(PROGRAM_NAME, "registering callback == calling esp_ble_gap_register_callback()");
//register the scan callback function to the gap module:
if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) {
ESP_LOGE(PROGRAM_NAME, "gap register error: %s", esp_err_to_name(status));
return;
} else {
ESP_LOGI(PROGRAM_NAME, "successful");
}
}
void ble_ibeacon_init(void)
{
esp_bluedroid_init();
esp_bluedroid_enable();
ble_ibeacon_appRegister();
}
//## BaseType_t timerOverflow = pdFALSE;
// IRAM_ATTR: Forces code into IRAM instead of flash
static bool IRAM_ATTR timer_alarm_cb ( gptimer_handle_t timer, const gptimer_alarm_event_data_t * edata, void * user_data ) { // == ISR on timer overflow event
/*
BaseType_t high_task_awoken = pdFALSE;
QueueHandle_t queue = (QueueHandle_t) user_data;
// Retrieve count value and send to queue
example_queue_element_t ele = {
.event_count = edata->count_value
};
xQueueSendFromISR(queue, &ele, &high_task_awoken);
// return whether we need to yield at the end of ISR
return (high_task_awoken == pdTRUE);
*/
//## timerOverflow = pdTRUE ; // #define pdTRUE ( ( BaseType_t ) 1 ) --> typedef portBASE_TYPE BaseType_t; --> #define portBASE_TYPE int
ESP_LOGI(PROGRAM_NAME, "1 s elapsed");
// #return Whether a high priority task has been waken up by this function:
return pdFALSE ;
}
// if prototype declared as "static bool IRAM_ATTR ..." --> error: no return statement in function returning non-void [-Werror=return-type]
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
esp_bt_controller_init(&bt_cfg);
esp_bt_controller_enable(ESP_BT_MODE_BLE);
ble_ibeacon_init();
/* set scan parameters */
#if (IBEACON_MODE == IBEACON_RECEIVER)
ESP_LOGI(PROGRAM_NAME, "setting RECEIVER scan parameters == calling esp_ble_gap_set_scan_params()");
esp_ble_gap_set_scan_params(&ble_scan_params);
#elif (IBEACON_MODE == IBEACON_SENDER)
esp_ble_ibeacon_t ibeacon_adv_data;
esp_err_t status = esp_ble_config_ibeacon_data (&vendor_config, &ibeacon_adv_data);
if (status == ESP_OK){
esp_ble_gap_config_adv_data_raw((uint8_t*)&ibeacon_adv_data, sizeof(ibeacon_adv_data));
}
else {
ESP_LOGE(PROGRAM_NAME, "Config iBeacon data failed: %s\n", esp_err_to_name(status));
}
#endif
// Creating a GPTimer Handle with Resolution (frequency) of 1 MHz:
ESP_LOGI(PROGRAM_NAME, "Creating new timer (handle)");
gptimer_handle_t gptimer = NULL;
gptimer_config_t timer_config = {
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
.direction = GPTIMER_COUNT_UP,
.resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 1us
};
ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));
// Prepare Triggering of Periodic Events (set up the alarm action before starting the timer !) every 1 sec:
ESP_LOGI(PROGRAM_NAME, "Setting alarm action");
gptimer_alarm_config_t alarm_config = {
.reload_count = 0, // counter will reload with 0 on alarm event
.alarm_count = 1000000, // period = 1s #resolution 1MHz
.flags.auto_reload_on_alarm = true, // enable auto-reload
};
ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));
ESP_LOGI(PROGRAM_NAME, "Registering callback function to execute on alarm event");
gptimer_event_callbacks_t cbs = {
.on_alarm = timer_alarm_cb, // register user callback
};
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
ESP_ERROR_CHECK(gptimer_enable(gptimer));
ESP_LOGI(PROGRAM_NAME, "Starting timer");
ESP_ERROR_CHECK(gptimer_start(gptimer));
/*
while ( 1 ) {
if ( timerOverflow ) {
timerOverflow = pdFALSE ;
ESP_LOGI(PROGRAM_NAME, "1 s elapsed");
}
}
*/
}
An example terminal output is:
/home/boko/.espressif/python_env/idf5.1_py3.10_envboko#boko-HP-EliteBook-850-G8-Notebook-PC:~/Desktop/ESP32/ble_ibeacon$ export IDF_PATH=/home/boko/esp/esp-idf
boko#boko-HP-EliteBook-850-G8-Notebook-PC:~/Desktop/ESP32/ble_ibeacon$ /home/boko/.espressif/python_env/idf5.1_py3.10_env/bin/python /home/boko/esp/esp-idf/tools/idf_monitor.py -p /dev/ttyUSB0 -b 115200 --toolchain-prefix xtensa-esp32s3-elf- --target esp32s3 /home/boko/Desktop/ESP32/ble_ibeacon/build/ble_ibeacon_demo.elf
--- idf_monitor on /dev/ttyUSB0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
) UUID:: fd a5�ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x16ac
load:0x403c9700,len:0xbc8
load:0x403cc700,len:0x2d64
entry 0x403c98fc
I (25) boot: ESP-IDF v5.1-dev-1626-g4b6d9c8ad3 2nd stage bootloader
I (25) boot: compile time Nov 11 2022 16:57:52
I (25) boot: chip revision: V001
I (29) boot_comm: chip revision: 1, min. bootloader chip revision: 0
I (36) boot.esp32s3: Boot SPI Speed : 80MHz
I (41) boot.esp32s3: SPI Mode : DIO
I (46) boot.esp32s3: SPI Flash Size : 2MB
I (51) boot: Enabling RNG early entropy source...
I (56) boot: Partition Table:
I (60) boot: ## Label Usage Type ST Offset Length
I (67) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (74) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (82) boot: 2 factory factory app 00 00 00010000 00100000
I (89) boot: End of partition table
I (93) boot_comm: chip revision: 1, min. application chip revision: 0
I (101) esp_image: segment 0: paddr=00010020 vaddr=3c080020 size=1e524h (124196) map
I (131) esp_image: segment 1: paddr=0002e54c vaddr=3fc96a00 size=01acch ( 6860) load
I (133) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=7514ch (479564) map
I (223) esp_image: segment 3: paddr=000a5174 vaddr=3fc984cc size=02484h ( 9348) load
I (225) esp_image: segment 4: paddr=000a7600 vaddr=40374000 size=12998h ( 76184) load
I (253) boot: Loaded app from partition at offset 0x10000
I (253) boot: Disabling RNG early entropy source...
I (265) cpu_start: Pro cpu up.
I (265) cpu_start: Starting app cpu, entry point is 0x403753cc
0x403753cc: call_start_cpu1 at /home/boko/esp/esp-idf/components/esp_system/port/cpu_start.c:146
I (0) cpu_start: App cpu up.
I (279) cpu_start: Pro cpu start user code
I (279) cpu_start: cpu freq: 160000000 Hz
I (280) cpu_start: Application information:
I (282) cpu_start: Project name: ble_ibeacon_demo
I (288) cpu_start: App version: 1
I (293) cpu_start: Compile time: Nov 11 2022 16:57:45
I (299) cpu_start: ELF file SHA256: 2432859c4fe13f02...
I (305) cpu_start: ESP-IDF: v5.1-dev-1626-g4b6d9c8ad3
I (311) heap_init: Initializing. RAM available for dynamic allocation:
I (318) heap_init: At 3FC9E8F8 len 0004AE18 (299 KiB): D/IRAM
I (325) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (332) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (338) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM
I (345) spi_flash: detected chip: generic
I (349) spi_flash: flash io: dio
W (353) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (366) coexist: coexist rom version e7ae62f
I (371) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (415) BT_INIT: BT controller compile version [76c24c9]
I (415) phy_init: phy_version 503,13653eb,Jun 1 2022,17:47:08
I (455) system_api: Base MAC address is not set
I (455) system_api: read default base MAC address from EFUSE
I (455) BT_INIT: Bluetooth MAC: 7c:df:a1:e3:55:fa
I (485) iBeacon2Omnicomm: registering callback == calling esp_ble_gap_register_callback()
I (485) iBeacon2Omnicomm: successful
I (485) iBeacon2Omnicomm: setting RECEIVER scan parameters == calling esp_ble_gap_set_scan_params()
I (495) iBeacon2Omnicomm: starting a scan == calling esp_ble_gap_start_scanning()
I (505) iBeacon2Omnicomm: Scan start successful
I (505) iBeacon2Omnicomm: Creating new timer (handle)
I (515) iBeacon2Omnicomm: Setting alarm action
I (515) iBeacon2Omnicomm: Registering callback function to execute on alarm event
I (525) iBeacon2Omnicomm: Starting timer
I (755) iBeacon2Omnicomm: iBeacon Found ==========
I (755) MAC address:: ac 23 3f a8 c3 a8
I (755) UUID:: fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25
I (765) iBeacon2Omnicomm: Major: 0x08ae (2222)
I (765) iBeacon2Omnicomm: Minor: 0x08ae (2222)
I (775) iBeacon2Omnicomm: RSSI:-48 dbm
I (805) iBeacon2Omnicomm: iBeacon Found ==========
I (805) MAC address:: ac 23 3f a8 c3 a8
I (805) UUID:: fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25
I (805) iBeacon2Omnicomm: Major: 0x04d2 (1234)
I (815) iBeacon2Omnicomm: Minor: 0x269e (9886)
I (815) iBeacon2Omnicomm: RSSI:-43 dbm
abort() was called at PC 0x403774b7 on core 0
0x403774b7: lock_acquire_generic at /home/boko/esp/esp-idf/components/newlib/locks.c:130
Backtrace: 0x40375ebe:0x3fc979f0 0x4037ec61:0x3fc97a10 0x403846a6:0x3fc97a30 0x403774b7:0x3fc97aa0 0x403775cd:0x3fc97ad0 0x4037769c:0x3fc97af0 0x420653c1:0x3fc97b20 0x42068505:0x3fc97e30 0x42075151:0x3fc97e60 0x40384555:0x3fc97e90 0x40377b75:0x3fc97ee0 0x40379d85:0x3fc97f00 0x40377295:0x3fc97f30 0x4037d8a7:0x3fcf3fb0 0x42003bc2:0x3fcf3fd0 0x40380151:0x3fcf3ff0 0x4038195d:0x3fcf4010
0x40375ebe: panic_abort at /home/boko/esp/esp-idf/components/esp_system/panic.c:423
0x4037ec61: esp_system_abort at /home/boko/esp/esp-idf/components/esp_system/esp_system.c:135
0x403846a6: abort at /home/boko/esp/esp-idf/components/newlib/abort.c:38
0x403774b7: lock_acquire_generic at /home/boko/esp/esp-idf/components/newlib/locks.c:130
0x403775cd: _lock_acquire_recursive at /home/boko/esp/esp-idf/components/newlib/locks.c:158
0x4037769c: __retarget_lock_acquire_recursive at /home/boko/esp/esp-idf/components/newlib/locks.c:314 (discriminator 3)
0x420653c1: _vfprintf_r at ??:?
0x42068505: vprintf at /builds/idf/crosstool-NG/.build/xtensa-esp32s3-elf/src/newlib/newlib/libc/stdio/vprintf.c:34 (discriminator 5)
0x42075151: esp_log_writev at /home/boko/esp/esp-idf/components/log/log.c:200
0x40384555: esp_log_write at /home/boko/esp/esp-idf/components/log/log.c:210
0x40377b75: timer_alarm_cb at /home/boko/Desktop/ESP32/ble_ibeacon/main/ibeacon_demo.c:200
0x40379d85: gptimer_default_isr at /home/boko/esp/esp-idf/components/driver/gptimer.c:512
0x40377295: _xt_lowint1 at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/xtensa_vectors.S:1118
0x4037d8a7: xt_utils_wait_for_intr at /home/boko/esp/esp-idf/components/xtensa/include/xt_utils.h:81
(inlined by) esp_cpu_wait_for_intr at /home/boko/esp/esp-idf/components/esp_hw_support/cpu.c:115
0x42003bc2: esp_vApplicationIdleHook at /home/boko/esp/esp-idf/components/esp_system/freertos_hooks.c:59
0x40380151: prvIdleTask at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:4273 (discriminator 1)
0x4038195d: vPortTaskWrapper at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:152
ELF file SHA256: 2432859c4fe13f02
Rebooting...
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x3 (RTC_SW_SYS_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x4037585c
0x4037585c: esp_restart_noos_dig at /home/boko/esp/esp-idf/components/esp_system/esp_system.c:46 (discriminator 1)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x16ac
load:0x403c9700,len:0xbc8
load:0x403cc700,len:0x2d64
entry 0x403c98fc
I (29) boot: ESP-IDF v5.1-dev-1626-g4b6d9c8ad3 2nd stage bootloader
I (29) boot: compile time Nov 11 2022 16:57:52
I (30) boot: chip revision: V001
I (34) boot_comm: chip revision: 1, min. bootloader chip revision: 0
I (41) boot.esp32s3: Boot SPI Speed : 80MHz
I (46) boot.esp32s3: SPI Mode : DIO
I (50) boot.esp32s3: SPI Flash Size : 2MB
I (55) boot: Enabling RNG early entropy source...
I (60) boot: Partition Table:
I (64) boot: ## Label Usage Type ST Offset Length
I (79) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (86) boot: 2 factory factory app 00 00 00010000 00100000
I (94) boot: End of partition table
I (98) boot_comm: chip revision: 1, min. application chip revision: 0
I (105) esp_image: segment 0: paddr=00010020 vaddr=3c080020 size=1e524h (124196) map
I (136) esp_image: segment 1: paddr=0002e54c vaddr=3fc96a00 size=01acch ( 6860) load
I (138) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=7514ch (479564) map
I (228) esp_image: segment 3: paddr=000a5174 vaddr=3fc984cc size=02484h ( 9348) load
I (230) esp_image: segment 4: paddr=000a7600 vaddr=40374000 size=12998h ( 76184) load
I (258) boot: Loaded app from partition at offset 0x10000
I (258) boot: Disabling RNG early entropy source...
I (269) cpu_start: Pro cpu up.
I (269) cpu_start: Starting app cpu, entry point is 0x403753cc
0x403753cc: call_start_cpu1 at /home/boko/esp/esp-idf/components/esp_system/port/cpu_start.c:146
I (0) cpu_start: App cpu up.
I (284) cpu_start: Pro cpu start user code
I (284) cpu_start: cpu freq: 160000000 Hz
I (284) cpu_start: Application information:
I (287) cpu_start: Project name: ble_ibeacon_demo
I (293) cpu_start: App version: 1
I (297) cpu_start: Compile time: Nov 11 2022 16:57:45
I (303) cpu_start: ELF file SHA256: 2432859c4fe13f02...
I (309) cpu_start: ESP-IDF: v5.1-dev-1626-g4b6d9c8ad3
I (316) heap_init: Initializing. RAM available for dynamic allocation:
I (323) heap_init: At 3FC9E8F8 len 0004AE18 (299 KiB): D/IRAM
I (329) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (336) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (342) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM
I (349) spi_flash: detected chip: generic
I (353) spi_flash: flash io: dio
W (357) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (371) coexist: coexist rom version e7ae62f
I (375) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (420) BT_INIT: BT controller compile version [76c24c9]
I (420) phy_init: phy_version 503,13653eb,Jun 1 2022,17:47:08
I (460) system_api: Base MAC address is not set
I (460) system_api: read default base MAC address from EFUSE
I (460) BT_INIT: Bluetooth MAC: 7c:df:a1:e3:55:fa
I (490) iBeacon2Omnicomm: registering callback == calling esp_ble_gap_register_callback()
I (490) iBeacon2Omnicomm: successful
I (490) iBeacon2Omnicomm: setting RECEIVER scan parameters == calling esp_ble_gap_set_scan_params()
I (500) iBeacon2Omnicomm: starting a scan == calling esp_ble_gap_start_scanning()
I (510) iBeacon2Omnicomm: Scan start successful
I (510) iBeacon2Omnicomm: Creating new timer (handle)
I (520) iBeacon2Omnicomm: Setting alarm action
I (520) iBeacon2Omnicomm: Registering callback function to execute on alarm event
I (530) iBeacon2Omnicomm: Starting timer
I (580) iBeacon2Omnicomm: iBeacon Found ==========
I (580) MAC address:: ac 23 3f a8 c3 a8
I (580) UUID:: fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25
I (590) iBeacon2Omnicomm: Major: 0x2711 (10001)
I (590) iBeacon2Omnicomm: Minor: 0x4cb9 (19641)
I (600) iBeacon2Omnicomm: RSSI:-37 dbm
I (1220) iBeacon2Omnicomm: iBeacon Found ==========
I (1220) MAC address:: ac 23 3f a8 c3 a8
I (1220) UUID:: fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25
I (1230) iBeacon2Omnicomm: Major: 0x04d2 (1234)
I (1230) iBeacon2Omnicomm: Minor: 0x269e (9886)
I (1240) iBeacon2Omnicomm: RSSI:-51 dbm
abort() was called at PC 0x403774b7 on core 0
0x403774b7: lock_acquire_generic at /home/boko/esp/esp-idf/components/newlib/locks.c:130
Backtrace: 0x40375ebe:0x3fc979f0 0x4037ec61:0x3fc97a10 0x403846a6:0x3fc97a30 0x403774b7:0x3fc97aa0 0x403775cd:0x3fc97ad0 0x4037769c:0x3fc97af0 0x420653c1:0x3fc97b20 0x42068505:0x3fc97e30 0x42075151:0x3fc97e60 0x40384555:0x3fc97e90 0x40377b75:0x3fc97ee0 0x40379d85:0x3fc97f00 0x40377295:0x3fc97f30 0x4037d8a7:0x3fcf3fb0 0x42003bc2:0x3fcf3fd0 0x40380151:0x3fcf3ff0 0x4038195d:0x3fcf4010
0x40375ebe: panic_abort at /home/boko/esp/esp-idf/components/esp_system/panic.c:423
0x4037ec61: esp_system_abort at /home/boko/esp/esp-idf/components/esp_system/esp_system.c:135
0x403846a6: abort at /home/boko/esp/esp-idf/components/newlib/abort.c:38
0x403774b7: lock_acquire_generic at /home/boko/esp/esp-idf/components/newlib/locks.c:130
0x403775cd: _lock_acquire_recursive at /home/boko/esp/esp-idf/components/newlib/locks.c:158
0x4037769c: __retarget_lock_acquire_recursive at /home/boko/esp/esp-idf/components/newlib/locks.c:314 (discriminator 3)
0x420653c1: _vfprintf_r at ??:?
0x42068505: vprintf at /builds/idf/crosstool-NG/.build/xtensa-esp32s3-elf/src/newlib/newlib/libc/stdio/vprintf.c:34 (discriminator 5)
0x42075151: esp_log_writev at /home/boko/esp/esp-idf/components/log/log.c:200
0x40384555: esp_log_write at /home/boko/esp/esp-idf/components/log/log.c:210
0x40377b75: timer_alarm_cb at /home/boko/Desktop/ESP32/ble_ibeacon/main/ibeacon_demo.c:200
0x40379d85: gptimer_default_isr at /home/boko/esp/esp-idf/components/driver/gptimer.c:512
0x40377295: _xt_lowint1 at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/xtensa_vectors.S:1118
0x4037d8a7: xt_utils_wait_for_intr at /home/boko/esp/esp-idf/components/xtensa/include/xt_utils.h:81
(inlined by) esp_cpu_wait_for_intr at /home/boko/esp/esp-idf/components/esp_hw_support/cpu.c:115
0x42003bc2: esp_vApplicationIdleHook at /home/boko/esp/esp-idf/components/esp_system/freertos_hooks.c:59
0x40380151: prvIdleTask at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:4273 (discriminator 1)
0x4038195d: vPortTaskWrapper at /home/boko/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:152
You're trying to log from within a General Purpose Timer interrupt. Quoting from documentation for Logging library:
This function or these macros should not be used from an interrupt.
There's also a longer comment from an Espressif developer explaining why. There seems to be another macro ESP_DRAM_LOGE for printing from within an interrupt (which is usually not a good idea).
Anyway, for anything except the most stringent real-time criteria I'd recommend using the High Resolution Timer instead. It's still run on top of the hardware timer peripheral, but processing of callbacks is deferred to a dedicated timer task (yes, you have to wait for a short time until the scheduler gets around to executing that task). This means your callbacks run in a regular task and can call logging functions. Don't go overboard - you still want the deferred timer callbacks to be reasonably quick to avoid timing jittering.
I need help in calculating modbus CRC check for function code 1. I.e read coil register. I have sample code for CRC check for function code 3 i.e holding register for analog input.
# Read Coil Status (FC=01)
## Request
This command is requesting the ON/OFF status of discrete coils # 20 to 56
from the slave device with address 17.
11 01 0013 0025 0E84
11: The Slave Address (17 = 11 hex)
01: The Function Code (read Coil Status)
0013: The Data Address of the first coil to read. (Coil 20 - 1 = 19 = 13 hex)
0025: The total number of coils requested. (coils 20 to 56 = 37 = 25 hex)
0E84: The CRC (cyclic redundancy check) for error checking.
Response
11 01 05 CD6BB20E1B 45E6
11: The Slave Address (17 = 11 hex)
01: The Function Code (read Coil Status)
05: The number of data bytes to follow (37 Coils / 8 bits per byte = 5 bytes)
CD: Coils 27 - 20 (1100 1101)
6B: Coils 35 - 28 (0110 1011)
B2: Coils 43 - 36 (1011 0010)
0E: Coils 51 - 44 (0000 1110)
1B: 3 space holders & Coils 56 - 52 (0001 1011)
45E6: The CRC (cyclic redundancy check).
Read Holding Registers (FC=03)
Request
This command is requesting the content of analog output holding registers # 40108 to
40110 from the slave device with address 17.
11 03 006B 0003 7687
11: The Slave Address (17 = 11 hex)
03: The Function Code (read Analog Output Holding Registers)
006B: The Data Address of the first register requested. (40108-40001 = 107 = 6B hex)
0003: The total number of registers requested. (read 3 registers 40108 to 40110)
7687: The CRC (cyclic redundancy check) for error checking.
Response
11 03 06 AE41 5652 4340 49AD
11: The Slave Address (17 = 11 hex)
03: The Function Code (read Analog Output Holding Registers)
06: The number of data bytes to follow (3 registers x 2 bytes each = 6 bytes)
AE41: The contents of register 40108
5652: The contents of register 40109
4340: The contents of register 40110
49AD: The CRC (cyclic redundancy check).
I am no issue for getting response for FC3. because i am sending properly the 2 byte address , but i dont know how can i send single byte and modify crc function for FC1 ->read coil register
Discription of read coil register
unsigned int crc_fn(unsigned char *dpacket,unsigned int len) { // CRC Function(Error calcualtion)
unsigned int crc = 0xffff,poly = 0xa001;
unsigned int i=0;
for(i=0; i<len; i++) {
crc^= dpacket[i];
for(j=0; j<8; j++) {
if(crc & 0x01) {
crc >>= 1;
crc ^= poly;
} else
crc >>= 1;
}
}
return (crc);
}
CRC is normally appended to a message most significant byte first. You need to swap two lines of code, sending the high order byte of the 16 bit crc before the low order byte. Try this change:
Serial_1_Send_byte((unsigned char)(crc1>>8));
Serial_1_Send_byte((unsigned char)crc1);
I have to implement a Modbus TCP using a TI Launchpad board which is similar to Arduino. I have the following snippet.
MbmByteArray[0] = 0x00;
MbmByteArray[1] = 0x01;
MbmByteArray[2] = 0x00;
MbmByteArray[3] = 0x00;
MbmByteArray[4] = 0x00;
MbmByteArray[5] = 0x0B;
MbmByteArray[6] = 0x01;
MbmByteArray[7] = 0x10;
MbmByteArray[8] = 0x00;
MbmByteArray[9] = 0x00;
MbmByteArray[10] = 0x00;
MbmByteArray[11] = 0x02;
MbmByteArray[12] = 0x04;
MbmByteArray[13] = 0x00;
MbmByteArray[14] = 0x08;
MbmByteArray[15] = 0x00;
MbmByteArray[16] = 0x00;
Serial.println("Written:");
for(int i=0;i<MbmByteArray[5]+6;i++) {
int a=0;
a = MbmClient.write(MbmByteArray[i]);
if(a)
{
// if something is written to the client I check what it is !
Serial.println(MbmByteArray[i]);
}
}
This is my client
You can see that the bytes are not received continuously. But my entire array is like a command to the client. Is there anyway to get it this way :
2016-06-17 14:28:00.252: Session created
2016-06-17 14:28:00.254: Session opened
2016-06-17 14:28:00.256: 17 bytes received
00 01 00 00 00 0B 01 10 00 00 00 02 04 00 07 00 00
2016-06-17 14:28:00.269: 12 bytes sent
< 00 01 00 00 00 06 01 10 00 00 00 02
Please help!
In general, when doing communication on any given line, file or media, you risk breaking up the data. Ethernet actually has a package size (MTU) that can/will be delivered unbroken. But that's another story. It'll be better if you deal with the issue, no matter protocol, hardware or platform. (Or at least be aware of it.)
When you read your ModbusTCP, you should make something like the following pseudo:
//read all ModbusTCP header
while less than 6 bytes received and not timed out and not error
read bytes
//read data
data_length = modbustcp_header position 5 and 6
while less than data_length and not timed out and not error
read bytes
The above function will collect the whole package, before "releasing" it to your engine. The algorithm will work for both sides of your setup. (Both the Texas hw and the PC.)
You could also (most likely) fiddle with the TI TCP stack and make it return bigger blocks. And I guess this was what you were asking for. But again, I wouldn't recommend going down that road.
Thank you Illishar !
I found a way to do it. In Arduino there is a client function, that could send the entire array without sending one value at a time.
byte command[17] = {0x00,0x01,0x00,0x00,0x00,0x0B,0x01,0x10,0x00,0x00,0x00,0x02,0x04,0x00,0x07,0x00,0x00};
MbmClient.write(command,17);
This client.write(buffer,number of elements) helps me to send the entire content in a single packet. It works like a charm :)
I'm writing code to configure the serial port on a pic32 family device. The initialization appears to work for the most part, but I get garbage data in place of the first 6 characters that I write. I noticed, however, that if I add an arbitrarily long wait at the end of the initialization function, this goes away. Is there some register flag that I need to be waiting on at the end of my initialization? My initialization code is below. If it helps, I am basing this initialization off of the UART section in the pic32 reference manual. I added the code below for my transmission function as well. My expected output string is "Hello from the bootloader code.\r\n" but the actual bytes I get are:
00000000 00 00 aa b1 b1 bd 81 66 72 6f 6d 20 74 68 65 20 |.......from the |
00000010 62 6f 6f 74 6c 6f 61 64 65 72 20 63 6f 64 65 2e |bootloader code.|
00000020 0d 0a
void initializeUART2()
{
uint32 counter;
initialized = TRUE;
U2MODE = 0;
U2STA = 0;
U2BRG = 0;
IEC1bits.U2TXIE = 0;
IEC1bits.U2RXIE = 0;
IEC1bits.U2EIE = 0;
//disable UART transmission before config
U2STA &= ~UART_TRANSMIT_ENABLED_STATUS_FLAG;
//disable UART before config
U2MODE &= ~UART_ENABLED_MODE_FLAG;
RS232_RS485_TRIS=0; //set to output
RS232_RS485=0; //select RS-232 mode on MAX3161
//set baudrate BAUDRATE = CLOCK_FREQUENCY/(16*(U2BRG + 1))
//solve for U2BRG value
U2BRG = (UINT16)(((PERIPHERAL_CLOCK_FREQUENCY/UART2_BAUDRATE)/16)-1);
//set mode to 8 bit no parity
U2MODE &= ~UART_PARITY_DATA_MODE_BITS;
//set number of stop bits to 1
U2MODE &= ~UART_EXTRA_STOP_MODE_BIT_FLAG;
//enable the UART port
U2MODE |= UART_ENABLED_MODE_FLAG;
//enable serial transmission
U2STA |= UART_TRANSMIT_ENABLED_STATUS_FLAG;
//without this loop, I get garbage in first 6 bytes of my first message
counter = 1000;
while(counter--);
}
void putUART2(uint32 value)
{
if(!initialized)
{
initializeUART2();
}
//make sure value is in range of writable values
value &= UINT32_MASK(8);
//clear transmit interrupt flag
IFS1bits.U2TXIF = 0;
//wait for the transmit buffer to be empty
while((U2STA & UART_TRANSMIT_STATUS_FLAG) == 0);
//set the data byte to be written in the write register
//also starts transmission
U2TXREG = value;
//wait for the transmit buffer to be empty
//both of these waits are necessary to avoid missing bytes
while((U2STA & UART_TRANSMIT_STATUS_FLAG) == 0);
}
The MAX3161 needs at least 100 ns to stabilize after switching modes to RS232.
Also, these lines:
RS232_RS485_TRIS=0; //set to output
RS232_RS485=0; //select RS-232 mode on MAX3161
should be reversed; set the output, then the direction register to avoid glitches.
Suspect the MAX3161 chip, which has charge pumps, needs the additional time to reach stable operating voltages.
It may be only for a bit time or 2, but if a message is sent too early, the serial output is messed until a quiet time occurs.
Lesser candidate: problem is an interaction between this and the unposted send routine.
Note: It's amazing how seeing using info like the unposted "garbage data" may help. Also knowing what the "good" first 6 bytes or so is useful.
[Edit] #Doug Currie is on the right track.
When RS232_RS485_TRIS1 is changed to output, a delay time as he suggest is needed before data is sent. This applies here as well as other place in code.
Further, before RS232_RS485_TRIS1 is changed to input, code needs to insure all the data is completely transmitted. This may be a 10/baud after the the PIC declares the xmit buffer empty. Or check the proper xmit status bit before turning the bus around. (Shift Register empty - names vary depending on compiler.)