Skip to content

tone crashes Pi 2040 #409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
fabltd opened this issue Feb 21, 2022 · 12 comments
Open

tone crashes Pi 2040 #409

fabltd opened this issue Feb 21, 2022 · 12 comments

Comments

@fabltd
Copy link

fabltd commented Feb 21, 2022

Hi All

Trying to use the inbuilt - tone function.

This will casue the PI 2040 to crash and can only be recovered by putting into disk mode.

Any suggestions to diagnose.

Does the tone function only work on certian pins?

Thanks

@facchinm
Copy link
Member

Hi @fabltd ,
can you share the sketch that provokes the crash (and the core version you are using)?
There's no limitation on the pins you can use since there's only one timer that takes care of all the pin toggling.
This sketch for example doesn't crash using core 2.7.2

void setup() {
  Serial.begin(115200);
  while (!Serial);
  for (int i = 0; i < 14; i++) {
    Serial.println("Tone on " + String(i));
    tone(i, 100);
    delay(100);
    noTone(i);
  }
}

void loop() {
}

@AndyLindsay
Copy link

AndyLindsay commented Feb 24, 2022

With core 2.7.2, the sketch below runs fine in my Raspberry Pi Pico, both immediately after the Upload and also when pin 30 (the RUN pin) is toggled. Additionally, it does not matter if the Pico is or is not connected to USB.

If delay(1000) is commented out, there is still no problem running the sketch when USB is disconnected. However, if the USB is left connected, then the results become unpredictable.

With USB connected, and without the delay(1000), sometimes the first note is crackly, but it completes the rest of the sketch. In this case, more sketch Uploads can be performed. Other times, the first note is crackly, but it doesn't play any more notes. If it stops after a crackly first note, it also goes into a mode where the LED repeatedly flashes rapidly 4 times, then slowly 4 times. In #316, @facchinm explained the blink sequence is signaling an RTOS crash and recommended a crash report, which I added below the sketch.

Side note: If it's signaling an RTOS crash, my Windows Arduino IDE 1.8.19 reports: "An error occurred while uploading the sketch." Another way to get back to being able to upload sketches is to put it into disk mode, as @fabltd reported.

Responses to toggling the RUN pin with USB connected and without delay(1000) are similar to when the Arduino IDE's Upload button is clicked. Sometimes, the first note plays but sounds crackly, followed by the RTOS crash LED signal. Other times, the first note is crackly, but it completes the sketch. When this occurs, the Arduino IDE can successfully Upload to the Raspberry Pi Pico again.

int note[] = {1047, 1147, 1319, 1397, 1568, 1760, 1976, 2093};

void setup()
{
  delay(1000);  // <-- Comment this for issues w/USB connected
  for(int index = 0; index < 8; index++)
  {
    tone(4, note[index], 500);               
    delay(750);                                
  }
}

void loop()
{
}

Crash Report

++ MbedOS Error Info ++

Error Status: 0x8015010E Code: 270 Module: 21

Error Message: The stack is waiting on a user callback for the buffer to fill or statu
s.

Location: 0x10007913

Error Value: 0x0

Current Thread: rtx_idle Id: 0x2000A67C Entry: 0x10006561 StackSize: 0x200 StackMem: 0
x20009038 SP: 0x2003FF14

For more info, visit: https://mbed.com/s/error?error=0x8015010E&osver=61501&core=0x410
CC601&comp=2&ver=110200&tgt=RASPBERRY_PI...



-- MbedOS Error Info --

@fabltd
Copy link
Author

fabltd commented Feb 24, 2022

Hi

How do I enable the crash dump. I am using platform IO?

@AndyLindsay
Copy link

If the Raspberry Pi Pico crashes, it'll transmit crash report data from pin 1 (GP0) at 115200 bits/s. Here are four ways to capture that data:

Arduino UNO as a serial passthrough
The Arduino Uno, Mega, and some others have shared hardware connections between the onboard USB/serial converter and digital pins 0/1. With those Arduino boards, any sketch that does not send/receive Serial Monitor messages or perform any I/O operations on DIGITAL pins 0 and 1 will allow it to behave like a USB/serial converter.

  1. Connect Pico pin 1 (GP0) to the Arduino UNO TX->1 socket in the DIGITAL header.
  2. Connect Pico GND to Arduino UNO GND.
  3. Complete steps 4 through 7 in the Arduino IDE:
  4. Click Tools, and set the Board to Arduino Uno.
  5. Click Tools, and set the Port to the one with (Arduino Uno) to the right of it.
  6. Open File, Examples, Basics, BareMinimum in the Arduino IDE and Upload it to the Uno.
  7. Open the Serial Monitor connected to the Uno, and change the rate dropdown from 9600 baud to 115200 baud.
  8. Toggle the Pico's RUN pin until the error occurs.
  9. The crash report should appear in the Serial Monitor.

Other Arduino devices as serial passthroughs
For Arduino boards without the hardware USB/serial connections, here is a SerialPassthrough sketch. Change Serial1.begin(9600) to Serial1.begin(115200).

USB/Serial Converter
If you have a USB/serial converter in your toolbox, just connect converter GND to Pico GND, and converter serial input to Pico pin 1 (GP0). Then, open a your computer's serial terminal app of choice and set it to the USB/serial device's port and its baud rate to 115200.

Raspberry Pi serial example
See section 2.2. Connecting from a Raspberry Pi in UART in Raspberry Pi Pico SDK.

@Gerriko
Copy link
Contributor

Gerriko commented May 30, 2022

I spotted this issue while I was revisiting an issue posted a year ago: #246
This related to core 1.

I tested my Raspberry Pi Pico board using the tone melody example and it works fine. My code is as follows (I'm using GPIO18):

/*
  Melody: Plays a melody
  circuit:
  - 8 ohm speaker on digital pin 8

  created 21 Jan 2010
  modified 30 Aug 2011
  by Tom Igoe

  This example code is in the public domain.
  https://www.arduino.cc/en/Tutorial/BuiltInExamples/toneMelody
*/

#include "pitches.h"

// notes in the melody:
int melody[] = {
  NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4
};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
  4, 8, 8, 4, 4, 4, 4, 4
};

void setup() {
  
}

void loop() {
  // no need to repeat the melody.
  // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < 8; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000 / noteDurations[thisNote];
    tone(18, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(18);
  }
  delay(500);
}

However, looking at the tone library for mbed, there may be scope to change the library. For example, I see that a new pin declaration is made everytime tone is called (pin = new mbed::DigitalOut(_pin);), which may be the cause of the above problem.

I have reasoned, but cannot come up with a suitable change, is that the problem caused for core1 relates to how
mbed::Timer, mbed::Timeout and mbed::Ticker are declared and then used in various callback functions. Maybe a custom template function can be created for callback, who knows.

@Gerriko
Copy link
Contributor

Gerriko commented May 30, 2022

Oh yes, in the original example provided above, which created the crash, I see there is a noTone(4); missing, which has to be inserted to detach the ticker object before a new tone object can be created otherwise the code tries to duplicate with a new ticker object, which will crash mbedOS.

@Kyklas
Copy link

Kyklas commented Jun 5, 2022

@AndyLindsay I have facing the same issue.
I am using Seeed XIAO RP2040 and the RP2040 on RaspberryPi Pico.

I have connected the UART and SWD to validated that the hang is a software issue and not related with my hardware.

++ MbedOS Error Info ++
Error Status: 0x8015010E Code: 270 Module: 21
Error Message: The stack is waiting on a user callback for the buffer to fill or status.
Location: 0x100088DB
Error Value: 0x0
Current Thread: main Id: 0x2000A6A4 Entry: 0x1000760D StackSize: 0x8000 StackMem: 0x20000FE0 SP: 0x2003FF14
For more info, visit: https://mbed.com/s/error?error=0x8015010E&osver=61501&core=0x410CC601&comp=2&ver=110300&tgt=RASPBERRY_PI...

-- MbedOS Error Info --

The issue occurs intermittently when booting with USB connected and when triggering reset

Forcing reset using 1200bps open/close on port COM16

I am driving neopixel using the Adafruit library ( I could use something better than bitbanging on RP2040, that would be for later ).

I am using packages\arduino\hardware\mbed_rp2040\3.1.1
I wanted to understand the blinking LED when the issue occurs.
Note sure which code is driving the LED blink.

OpenOCD with SWD indicated an error since mbed_halt_system is called from mbed_error.
https://github.com/ARMmbed/mbed-os/blob/master/platform/source/mbed_error.c

@facchinm
Copy link
Member

facchinm commented Jun 6, 2022

Hi @Kyklas ,
the problem you are experiencing is triggered by this line (https://github.com/arduino/mbed-os/blob/extrapatches-6.15.1/drivers/usb/source/USBDevice.cpp#L909).
It would be nice if you could provide the specification of your PC (like model and operating system version) since it's the first time we hear of this kind of issue and it definitely might be system dependent.

@Kyklas
Copy link

Kyklas commented Jun 12, 2022

@facchinm Thanks for the feedback.
I am on Window 10 21H2 build 19044.1706.
For USB information I often have USB Device Tree Viewer open which may cause additional USB request.
The issue also occurs with USB Device Tree Viewer closed.
Just tested it and right as I connect the USB I have the error on uart (Repro 5 time in a row).

Error Status: 0x8015010E Code: 270 Module: 21
Error Message: The stack is waiting on a user callback for the buffer to fill or status.

I am using Adafruit Neopixel to drive 60 LED across 3 bus.
That library may not be the best for RP2040, the loop execute a few time and them stops.

I just tested to connect the system to my android phone, same issue.
May not be a USB host issue. Curious to know what this would turn out to be.

@metehoca
Copy link

i have another problem with tone function with pi pico. after using notone function, buzzer's gpio stays high. that can cause lots of problems with some installations.

@PetteriAimonen
Copy link

I have traced this a bit, it appears to happen when USB is connected and interrupts have been disabled for a while.
Most typically if code enters some tight loop right after boot, because this is when the PC is trying to send a lot of USB setup requests.

It appears that USBDevice::_control_setup gets called, but the _complete_request callback scheduled through _run_later() / _post_process has not had a chance to run before another control request occurs.

The ep0_out handler is called from RP2040 USB PHY code. If there are any interrupts still set, the process() function handles them all before returning.

The RP2040 datasheet notes on page 427: "Buffer status register. A bit set here indicates that a buffer has completed on the endpoint (if the buffer interrupt is enabled). It is possible for 2 buffers to be completed, so clearing the buffer status bit may instantly re set it on the next clock cycle."

This means that the unlock() call in USBDevice::start_process() does not get a chance to run. The unlock call is what runs the _post_process callback.

So my theory is:

  1. RP2040 interrupts are disabled for long enough that host sends 2 USB EP0 requests.
  2. USBPhyHw::process() starts handling the first one. The request completion is scheduled to happen on unlock().
  3. Because there is another buffer queued, USBPhyHw::process() starts handling that also.
  4. The ep0_out() code detects that previous request handling has not yet completed, and throws mbed_error() with the message "The stack is waiting on a user callback for the buffer to fill or status.".

I'm not sure what is the correct fix - maybe handling only one interrupt per endpoint per one USBPhyHw::process() call?

@PetteriAimonen
Copy link

PetteriAimonen commented Mar 30, 2023

Traced a bit more with USB analyzer and using the XIP bus for execution tracing.

Time (ms)
    -1.9    Host sends SETUP EP0, RP2040 ACKs
            Payload 80: Device to host, standard device request
                    06: Request 6 = Get descriptor
                    00 02: Value = Configuration descriptor 0
                    00 00: Index
                    4B 00: Length

    -0.9    Host sends IN EP0, RP2040 responds with 64 bytes, ACK by host

     0.0    Code disables interrupts for flash writing
     
     0.1    Host sends IN EP0, RP2040 responds with 11 bytes, ACK by host
     1.1    Host sends OUT EP0, 0 bytes payload, ACK from RP2040
     2.1    Host sends SETUP EP0, ACK from RP2040
            Payload 80: Device to host, standard device request
                    06: Request 6 = Get descriptor
                    00 03: Value = String descriptor 0 (LANGID)
                    00 00: Index
                    FF 00: Length
     
     3.1    Host sends IN EP0, RP2040 sends NAK
     ...
     ...    SOF and IN EP0 / NAK repeats while IRQ disabled
     ...
    47.1    Host sends IN EP 0, RP2040 sends NAK
    
    47.5    Code enables interrupts
    47.5    USBPhyHw::_usbisr()  (code trace from XIP bus)
    47.60   USBPhyHw::process()
    47.61   USBDevice::ep0_setup()
    47.62   USBDevice::_control_setup()
    47.63   USBDevice::_control_setup()
    47.64   arduino::internal::PluggableUSBModule::assert_locked()
    47.65   USBDevice::complete_request()
    47.66   USBDevice::unlock()
    47.662  core_util_critical_section_exit()
    47.665  USBDevice::unlock()
    47.666  USBDevice::complete_request()
    47.667  USBDevice::ep0_setup()
    47.67   USBPhyHw::process()
    47.68   USBDevice::_control_in()
    47.69   USBDevice::ep0_out()
    47.7    mbed_error()
    
    48.1    Host sends IN EP 0, RP2040 sends STALL

Does not exactly match my theory. Looks like there is SETUP EP0 and OUT EP0 in the queue when interrupts are enabled. But I can see a call to unlock() so not sure why user_callback is not None. After the crash I can see it has value Request, and stage is Setup. Maybe it is waiting for the STALL to be sent?

Or maybe it is processing the new SETUP packet first, and is then getting confused by the 0-length status stage of previous SETUP? The SETUP comes before OUT in USBPhy_RP2040 process().

This problem makes it difficult to reprogram RP2040 external flash in a program that also uses USB. One workaround is to run everything from RAM, another is to sleep a bit after boot and hope that host is not communicating.

@facchinm Do you have any ideas?

PetteriAimonen added a commit to ZuluSCSI/ZuluSCSI-firmware that referenced this issue Mar 30, 2023
The SD-card bootloader occassionally crashed due to either:
- USB packets during flash writing (arduino/ArduinoCore-mbed#409)
- Some flash XIP issues when function is not in RAM.
erichelgeson pushed a commit to BlueSCSI/BlueSCSI-v2 that referenced this issue Apr 10, 2023
The SD-card bootloader occassionally crashed due to either:
- USB packets during flash writing (arduino/ArduinoCore-mbed#409)
- Some flash XIP issues when function is not in RAM.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants