USB Observations

JohnO
Sun May 21, 2017 3:29 pm
I am a newcomer to STM32duino and compiling on a Mac the USB behaves a little strangely when comparing power up USB enumeration and USB enumeration after the programming phase using the STM32duino bootloader.

I am using a Blue Pill (BP) with generic_boot20_pc13.bin loaded.
At power up and using “lsusb” the BP enumerates as “Bus 020 Device 014: ID 1eaf:0004 1eaf Maple”
and it is possible to connect serially to a device “/dev/cu.usbmodem1411”.

After programming a simple sketch “lsusb” shows the following device: “Bus 020 Device 024: ID 1eaf:0003 1eaf Maple 003 Serial: LLM 003”
at this point it is not possible to serial connect or reprogram without a hard reset of the BP. There is a clue at the end of the upload dialogue, “Resetting USB to switch back to runtime mode”.

Deducing device DFU version from functional descriptor length
Opening DFU capable USB device...
ID 1eaf:0003
Run-time device DFU version 0110
Claiming USB DFU Interface...
Setting Alternate Setting #2 ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 0110
Device returned transfer size 1024
Copying data from PC to DFU device

Download [ ] 0% 0 bytes
Download [= ] 6% 1024 bytes
Download [=== ] 13% 2048 bytes
Download [==== ] 19% 3072 bytes
Download [====== ] 26% 4096 bytes
Download [======== ] 33% 5120 bytes
Download [========= ] 39% 6144 bytes
Download [=========== ] 46% 7168 bytes
Download [============= ] 53% 8192 bytes
Download [============== ] 59% 9216 bytes
Download [================ ] 66% 10240 bytes
Download [================== ] 72% 11264 bytes
Download [=================== ] 79% 12288 bytes
Download [===================== ] 86% 13312 bytes
Download [======================= ] 92% 14336 bytes
Download [======================== ] 99% 14420 bytes
Download [=========================] 100% 14420 bytes
Download done.
state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
Done!
Resetting USB to switch back to runtime mode


ag123
Sun May 21, 2017 5:14 pm
press reset, it would go back into those fast/slow blinks for a while (dfu mode), then later jump to your sketch

hanyazou
Sun May 21, 2017 8:58 pm
Mac OS USB implementation and libusb (a library which is used by host tools) have a problem.
There is related topic to that issue. I’ve modified the bootloader for blue-pill to solve the problem.

Failed to reconnect serial monitor after uploading on macOS
http://www.stm32duino.com/viewtopic.php?f=21&t=2050

I attached the modified bootloader. Please try this if you can flash the bootloader to your blue-pill.


JohnO
Mon May 22, 2017 6:49 am
Thanks for your reply @hanyazou your modified bootloader has moved things on in that I can now upload the sketch a number of times without any need for any reset of the BP. The sketch I have tested outputs a stream of characters before entering a hard loop pending a reset. If, after programming I use the Arduino Serial Monitor the text is displayed correctly. However, intermittently after using Serial Monitor it is no longer possible to program the BP until a hardware reset:

/Users/johare/Documents/Arduino/hardware/Arduino_STM32/tools/macosx/maple_upload cu.usbmodem1411 2 1EAF:0003 /var/folders/6c/gxr4fz9s0_1cfcfnq7b8fmr40000gp/T/arduino_build_661694/rik.ino.bin
dfu-util 0.8

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2014 Tormod Volden and Stefan Schmidt
dfu-util: Invalid DFU suffix signature
This program is Free Software and has ABSOLUTELY NO WARRANTY
dfu-util: A valid DFU suffix will be required in a future dfu-util release!!!
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

Deducing device DFU version from functional descriptor length
dfu-util: No DFU capable USB device available
An error occurred while uploading the sketch


JohnO
Mon May 22, 2017 9:40 am
Looking into this a little further the sketch is still active and the Serial Monitor is able to reconnect to it. However, intermittently it isn’t possible to reprogram the sketch.
/Users/johare/Documents/Arduino/hardware/Arduino_STM32/tools/macosx/maple_upload cu.usbmodem1411 2 1EAF:0003 /var/folders/6c/gxr4fz9s0_1cfcfnq7b8fmr40000gp/T/arduino_build_661694/rik.ino.bin
dfu-util 0.8

dfu-util: Invalid DFU suffix signature
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
dfu-util: A valid DFU suffix will be required in a future dfu-util release!!!
Copyright 2010-2014 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

Deducing device DFU version from functional descriptor length
Opening DFU capable USB device...
ID 1eaf:0003
Run-time device DFU version 0110
Claiming USB DFU Interface...
Setting Alternate Setting #2 ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 0110
Device returned transfer size 1024
Copying data from PC to DFU device

Download [ ] 0% 0 bytes
Download [= ] 6% 1024 bytes
Download [=== ] 13% 2048 bytes
Download [==== ] 19% 3072 bytes
Download [====== ] 26% 4096 bytes
Download [======== ] 33% 5120 bytes
Download [========= ] 39% 6144 bytes
Download [=========== ] 46% 7168 bytes
Download [============= ] 52% 8192 bytes
Download [============== ] 59% 9216 bytes
Download [================ ] 66% 10240 bytes
Download [================== ] 72% 11264 bytes
Download [=================== ] 79% 12288 bytes
Download [===================== ] 86% 13312 bytesprocessing.app.SerialException: Error opening serial port '/dev/cu.usbmodem1411'.
at processing.app.Serial.<init>(Serial.java:125)
at processing.app.Serial.<init>(Serial.java:66)
at processing.app.SerialMonitor$3.<init>(SerialMonitor.java:93)
at processing.app.SerialMonitor.open(SerialMonitor.java:93)
at processing.app.AbstractMonitor.resume(AbstractMonitor.java:110)
at processing.app.Editor.resumeOrCloseSerialMonitor(Editor.java:2226)
at processing.app.Editor.access$2400(Editor.java:77)
at processing.app.Editor$DefaultExportHandler.run(Editor.java:2204)
at java.lang.Thread.run(Thread.java:745)
Caused by: jssc.SerialPortException: Port name - /dev/cu.usbmodem1411; Method name - openPort(); Exception type - Port not found.
at jssc.SerialPort.openPort(SerialPort.java:167)
at processing.app.Serial.<init>(Serial.java:114)
... 8 more
Error opening serial port '/dev/cu.usbmodem1411'.

Download [======================= ] 92% 14336 bytes
Download [======================== ] 99% 14444 bytes
Download [=========================] 100% 14444 bytes
Download done.
state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
Done!
Resetting USB to switch back to runtime mode


JohnO
Mon May 22, 2017 9:59 am
There is a lot going on here that is way outside my grasp. Adding a delay as the first line of setup() prevents further programming:
void setup() {
delay(1000);
//Initialize USBSerial and wait for port to open:
Serial.begin();
.
.

hanyazou
Mon May 22, 2017 1:15 pm
Deducing device DFU version from functional descriptor length
dfu-util: No DFU capable USB device available
An error occurred while uploading the sketch

Rick Kimball
Mon May 22, 2017 1:29 pm
JohnO wrote:Looking into this a little further the sketch is still active and the Serial Monitor is able to reconnect to it. However, intermittently it isn’t possible to reprogram the sketch.
...
Download [================== ] 72% 11264 bytes
Download [=================== ] 79% 12288 bytes
Download [===================== ] 86% 13312 bytesprocessing.app.SerialException: Error opening serial port '/dev/cu.usbmodem1411'.
at processing.app.Serial.<init>(Serial.java:125)
at processing.app.Serial.<init>(Serial.java:66)
at processing.app.SerialMonitor$3.<init>(SerialMonitor.java:93)
at processing.app.SerialMonitor.open(SerialMonitor.java:93)
at processing.app.AbstractMonitor.resume(AbstractMonitor.java:110)
at processing.app.Editor.resumeOrCloseSerialMonitor(Editor.java:2226)
at processing.app.Editor.access$2400(Editor.java:77)
at processing.app.Editor$DefaultExportHandler.run(Editor.java:2204)
at java.lang.Thread.run(Thread.java:745)
Caused by: jssc.SerialPortException: Port name - /dev/cu.usbmodem1411; Method name - openPort(); Exception type - Port not found.
at jssc.SerialPort.openPort(SerialPort.java:167)
at processing.app.Serial.<init>(Serial.java:114)
... 8 more
Error opening serial port '/dev/cu.usbmodem1411'.

Download [======================= ] 92% 14336 bytes
Download [======================== ] 99% 14444 bytes
Download [=========================] 100% 14444 bytes
Download done.
...


Rick Kimball
Mon May 22, 2017 1:31 pm
hanyazou wrote:
When you get this error of “dfu-util: No DFU capable USB device available”, you should check the red LED on the BP to see if the maple_upload reset the board successfully with the Arduino_STM32/tools/macosx/upload-reset utility.

hanyazou
Mon May 22, 2017 1:43 pm

This exact same thing happens to me if I leave the serial monitor open and then press the upload button.
The answer to this problem is to close the serial monitor window before you try to upload new code.

That is true if you use old Arduino IDE. Latest IDE will close a serial port automatically when you push the upload button and re-open the serial port again after uploading.


FWIW: my bluepill has a blue user led (PC13) and a red power led.

One of mine have blue power led and red user led. And another one of mine have red power led and green user led. :lol:


Rick Kimball
Mon May 22, 2017 2:33 pm
hanyazou wrote:
That is true if you use old Arduino IDE. Latest IDE will close a serial port automatically when you push the upload button and re-open the serial port again after uploading.

JohnO
Mon May 22, 2017 3:07 pm
hanyazou wrote:[
diff --git a/tools/macosx/maple_upload b/tools/macosx/maple_upload
index 8d15eff..ef581c8 100755
--- a/tools/macosx/maple_upload
+++ b/tools/macosx/maple_upload
@@ -50,4 +50,13 @@ if [ ! -x ${DFU_UTIL} ]; then
exit 2
fi

+echo ${DFU_UTIL} -d ${usbID} -a ${altID} -D ${binfile} -R ${dfuse_addr} -R
${DFU_UTIL} -d ${usbID} -a ${altID} -D ${binfile} -R ${dfuse_addr} -R
+
+# take a breath waiting for restarting the target device
+/bin/echo -n wait for ${dummy_port_fullpath}...
+while [ ! -c ${dummy_port_fullpath} ]; do
+ sleep 0.1
+done
+sleep 0.3
+echo done.


JohnO
Mon May 22, 2017 3:13 pm
Rick Kimball wrote:hanyazou wrote:
That is true if you use old Arduino IDE. Latest IDE will close a serial port automatically when you push the upload button and re-open the serial port again after uploading.

JohnO
Mon May 22, 2017 3:41 pm
JohnO wrote:
I still see an issue where a delay is used immediately after setup():
void setup() {
delay(1000);
//Initialize USBSerial and wait for port to open:
Serial.begin();

while (!Serial) { ; }
while (!Serial.isConnected() ) { ; }


danieleff
Mon May 22, 2017 3:45 pm
This actually works in Windows too, waiting 3 seconds at the end of win/maple_upload.bat (`ping -n 3 127.0.0.1 > nul`), and I do not have to close/reopen the serial monitor. (MapleMini, bootloader, Arduino 1.8.2)

JohnO
Mon May 22, 2017 3:57 pm
Another facet, with delays greater than 265 the boot loader is no longer responsive to attempts at programming. Need to hit hardware reset as soon as the programming phase is started.

–edit: Why is the bootloader affected by detail in the sketch?


JohnO
Mon May 22, 2017 4:06 pm
I have it, the Serial Monitor code only waits a short time for the Serial.begin(). If it doesn’t see the Serial.begin() the Serial Monitor screen stays blank. I don’t know what the sketch is actually doing.

–edit: Doesn’t explain the programming not working. Does the boot loader spend 265ms trying to set up the serial path before doing the programming?
void setup() {
//Initialize USBSerial and wait for port to open:
Serial.begin();
delay(1000);


danieleff
Mon May 22, 2017 4:15 pm
JohnO wrote:I have it, the Serial Monitor code only waits a short time for the Serial.begin(). If it doesn’t see the Serial.begin() the Serial Monitor screen stays blank. I don’t know what the sketch is actually doing.

–edit: Doesn’t explain the programming not working. Does the boot loader spend 265ms trying to set up the serial path before doing the programming?


JohnO
Mon May 22, 2017 4:20 pm
Excellent @danieleff!

–edit: Does that explain the programming? A delay greater than 0.265s in the sketch causes the programming to fail? I still don’t quite see it.


hanyazou
Mon May 22, 2017 6:17 pm
@JohnO
Are there any errors from maple_upload nor upload-reset? You can’t program if it fails to reset the board.

If you still have these two lines below in the setup(), they may block the sketch and upload-reset may not work. Because, upload-reset do open/close in 1200bps to notify resetting to the user application (sketch) running on the board and the sketch must handle the open/close in 1200bps properly.

while (!Serial) { ; }
while (!Serial.isConnected() ) { ; }


hanyazou
Mon May 22, 2017 6:34 pm
Rick Kimball wrote:
based on the debug output JohnO posted, it appears the IDE is trying to resume the serial port before the download is complete.

JohnO
Mon May 22, 2017 6:50 pm
Thanks @hanyazou, the sketch works fine with or without the two code lines you mention.

Am I correct to understand that Serial.begin must be in any sketch for the uploader/bootloader to function no matter that the sketch has no other need for serial?


hanyazou
Mon May 22, 2017 7:16 pm

Am I correct to understand that Serial.begin must be in any sketch for the uploader/bootloader to function no matter that the sketch has no other need for serial?

No, sorry. My understanding was not correct.
I can upload my simple sketch which does not include Serial.begin() repeatedly.

So, have all of your problems been solved? Is the longer wait of the bootloader needed?


JohnO
Mon May 22, 2017 7:35 pm
Your changes have improved my experience of STM32duino immensely.

However, I would like to understand why having a delay(1000) as the first line after setup() causes the subsequent program upload to fail. That is, if the active code loaded into flash contains delay(1000) as the first line in setup() then the next upload will fail with:

/Users/johare/Documents/Arduino/hardware/Arduino_STM32/tools/macosx/dfu-util/dfu-util -d 1EAF:0003 -a 2 -D /var/folders/6c/gxr4fz9s0_1cfcfnq7b8fmr40000gp/T/arduino_build_996/rik.ino.bin -R -R
dfu-util 0.8

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2014 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
dfu-util: Invalid DFU suffix signature

dfu-util: A valid DFU suffix will be required in a future dfu-util release!!!
Deducing device DFU version from functional descriptor length
dfu-util: No DFU capable USB device available
An error occurred while uploading the sketch


ag123
Mon May 22, 2017 10:01 pm
usually i tried a different approach, i wait for a keypress from the serial monitor
while(!Serial.available()) delay(10);

hanyazou
Mon May 22, 2017 10:34 pm

Have you been able to verify my experience in this?
Everything else is spot on.
It *feels* that the delay is preventing the bootloader from interacting with dfu-util.

No… I can upload this sketch repeatedly.

void setup() {
delay(1000); // 2000, 3000...
Serial.begin(9600);
while (!Serial);
Serial.println("Hello!");

// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
Serial.println("running...");
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}


ag123
Tue May 23, 2017 6:32 am
initially to diagnose issues, i tend to use dfu-util -l and dfu–util -a 2 -R -D sketch.bin
to install my sketches e.g.using a shell script
#!/bin/bash
dfu-util -l
dfu-util -a 2 -R -D $*

JohnO
Tue May 23, 2017 6:44 am
ag123 wrote:
for the maple mini boards, there is a (user) button (actually boot0 is *reused* for this purpose) that you can press to tell the bootloader to go into ‘perpetual boot loader mode’
this option is not feasible on bluepill because it is simply a jumper, if you set the boot0 jumper to high and press reset, it would drop into uart bootloader/install mode (this is ST’s native bootloader), not the stm32duino boot loader. to get into ‘perpetual boot loader’ mode would mean that you have to keep boot0 low when you press reset, and quickly set boot0 high *during* the fast blinks, this is very difficult short of making boot0 a button or switch for that matter

ag123
Tue May 23, 2017 7:42 am
i’m thinking that if serial monitor woes persist, we may be able to feedback to the arduino ide implementers to provide some ‘settings/preferences’ for the serial monitor so that perhaps a tunable delay can be configured to start serial monitor after a sketch install. this would perhaps solve some of the serial monitor issues

i’ve thought that normally serial monitor is manually started from the menu, isn’t it the case?

note that a sketch install is not necessary if it is simply to run the sketch, a reset on the blue pill/maple mini would restart the sketch.
to keep things more predictable, e.g. i’m anticipating prints on serial terminal, i often patch some codes to wait for key presses on the serial console before the rest of the sketch runs, the other tricks i often do with problematic sketches is to turn on the board led, this would give an indication if after all the sketch crashed e.g.//board led pin 33 PB1 on maple mini
#define BOARD_LED_PIN 33

void setup() {
Serial.begin(115200);
pinMode(BOARD_LED_PIN,OUTPUT);
digitalWrite(BOARD_LED_PIN,HIGH);

Serial.println("press any key to start");
while(!Serial.available()) delay(10);
digitalWrite(BOARD_LED_PIN,LOW); //led off after keypress is received
}


danieleff
Tue May 23, 2017 8:03 am
ag123 wrote:i’m thinking that if serial monitor woes persist, we may be able to feedback to the arduino ide implementers to provide some ‘settings/preferences’ for the serial monitor so that perhaps a tunable delay can be configured to start serial monitor after a sketch install. this would perhaps solve some of the serial monitor issues

i’ve thought that normally serial monitor is manually started from the menu, isn’t it the case?


JohnO
Tue May 23, 2017 8:18 am
hanyazou wrote:
Have you been able to verify my experience in this?
Everything else is spot on.
It *feels* that the delay is preventing the bootloader from interacting with dfu-util.

No… I can upload this sketch repeatedly.

void setup() {
delay(1000); // 2000, 3000...
Serial.begin(9600);
while (!Serial);
Serial.println("Hello!");

// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
Serial.println("running...");
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}


ag123
Tue May 23, 2017 8:21 am
thanks danieleff, hanyazou

i tried the patches by hanyazou, it is basically editing the shell script that’s part of the Arduino_STM32 core. i’m using linux opensuse 13.1
viewtopic.php?f=28&t=2107#p28441

it works pretty well with those patches to set a little delay after the sketch install

the shell script is part of Arduino/hardware/Arduino_STM32/tools/{macosx,linux,linux64,win}/maple_upload
hence we’d not need to wait for the arduino ide implementers to provide any fixes

i’m able to compile/uploaded a sketch and connect to it in serial terminal within the arduino ide after the patch.
(usb)serial is working as expected as well

@JohnO,
you may like to try the boot1 as ‘perpetual boot loader’ bootloader from roger’s repository
http://www.stm32duino.com/viewtopic.php … =20#p28466
this may help to keep the BP waiting for the install, instead of manually racing between pressing reset and clicking on sketch install on the arduino ide


ag123
Tue May 23, 2017 8:49 am
hi JohnO,

i tried your code with some additions to wait for a key press
apparently the delay before Serial.begin() has an impact.
if i set delay(450); before Serial.begin() the sketch still runs normally
however, if i set delay(500); before Serial.begin() the sketch stalls, the led remains on and is not responsive to the keypress (i.e. the led did not turn off) based on my key press wait

if however, if you place that delay(1000) after Serial.begin() everything works. this i think may have something to do with USB-Serial initialization on the host. perhaps too long a delay cause a timeout on the host and the host no longer treats that as a usb serial (i.e. CDC ACM) device.
hence, we should not put a delay before Serial.begin(). Serial.begin() should start as early as Setup() is initiated so that the usb-serial enumeration and initialization can start as soon as possible.

#include "Streaming.h" //http://arduiniana.org/libraries/streaming/

//board led pin 33 PB1 on maple mini
#define BOARD_LED_PIN 33

static const bool USE_STREAMING = true;

void setup() {
//delay(1000);
//Initialize USBSerial and wait for port to open:
Serial.begin();
delay(1000);

pinMode(BOARD_LED_PIN,OUTPUT);
digitalWrite(BOARD_LED_PIN,HIGH);

Serial.println("press any key to start");
while(!Serial.available()) delay(10);
digitalWrite(BOARD_LED_PIN,LOW); //led off after keypress is received

if ( USE_STREAMING ) {
Serial << "ASCII Table ~ Character Map" << endl;
}
else {
// prints title with ending line break
Serial.println("ASCII Table ~ Character Map");
}
}

// first visible ASCIIcharacter '!' is number 33:
int thisByte = 33;

void loop() {
if ( USE_STREAMING ) {
Serial << (char)thisByte
<< ", dec: " << _DEC(thisByte)
<< ", hex: " << _HEX(thisByte)
<< ", oct: " << _OCT(thisByte)
<< ", bin: " << _BIN(thisByte)
<< endl;
}
else {
Serial.write((char)thisByte);
Serial.print(", dec: ");
Serial.print(thisByte, DEC);
Serial.print(", hex: ");
Serial.print(thisByte, HEX);
Serial.print(", oct: ");
Serial.print(thisByte, OCT);
Serial.print(", bin: ");
Serial.println(thisByte, BIN);
}

if (thisByte == 126) { // you could also use if (thisByte == '~') {
// This loop loops forever and does nothing
// while (true) {
// delay(2000);
thisByte = 33;
// }
}
// go on to the next character
thisByte++;
}


JohnO
Tue May 23, 2017 9:08 am
I am relieved we are seeing the same symptoms. Don’t get me wrong I am very pleased with where we have got to.

My head struggles to accept that delay(1000) before Serial.begin should have these implications and I need to understand why this is happening before taking on board a workaround. Some sketches are not impacted by the delay while others screw up the programming, we have an issue here. If delay has these implications there may be others and debugging them in the *next* project may be even more difficult than unravelling it now.
The answer will be in the boot loader since the bootloader is releasing the user level code before it has completed its handling of start up.


ag123
Tue May 23, 2017 9:24 am
no worries, i’ve actually abandoned arduino ide for its serial troubles till i tried hanyazou’s fix today :lol:
i’ve been installing sketch manually using dfu-util and using an external serial terminal

i think hanyazou’s fixes in the dfu-install shell script should be commited to roger’s Arduino_STM32 repository, at least for linux and mac, i’m not sure about windows though

if Serial.begin() is not called as a default in the sketch initiation before setup() (this is in the libmaple core codes), this can be read as a ‘good thing’. i.e. if you need Serial, you need to call Serial.begin() as early as possible in setup();. in this way if you want to use usb for any other purposes, you could call usb_some_other_device_class.begin(), this would allow the Blue pill/Maple mini to be used as a ‘generic’ usb device, e.g. a different sketch makes BP/MM works as a different usb device serial/mass storage/HID/audio etc


JohnO
Tue May 23, 2017 9:32 am
Do you use build scripts as well as uploads? I take it you don’t have the delay issue with the scripts – I’ll give it a spin. If you have build scripts I would welcome a look.

ag123
Tue May 23, 2017 9:36 am
i’m not too sure about the build scripts, i made the patches as suggested in hanyazou patch : Arduino_STM32/tools/{macosx,linux64}/maple_upload.
the rest are ‘stock’ from Arduino_STM32

stevestrong
Tue May 23, 2017 9:37 am
I also observed once the issue with serial enumeration when using delay(1000) right in the beginning of setup(), before Serial.begin(), using Win 10.
So I can confirm, we may have an issue here.

ag123
Tue May 23, 2017 9:40 am
i think delay(n) should never be called before serial.begin(), calling delay(n) before Serial.begin() can cause the *host* to time out and no longer recognise the usb device

JohnO
Tue May 23, 2017 10:11 am
You script file shows a few devices:
Johns-MacBook-Pro:~ john$ ./dfu-install.sh /var/folders/6c/gxr4fz9s0_1cfcfnq7b8fmr40000gp/T/arduino_build_696853/rik.ino.bin
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

Deducing device DFU version from functional descriptor length
Found Runtime: [05ac:821d] ver=0154, devnum=8, cfg=1, intf=3, path="29-3", alt=0, name="UNKNOWN", serial="UNKNOWN"
Found DFU: [1eaf:0003] ver=0201, devnum=7, cfg=1, intf=0, path="20-2", alt=2, name="STM32duino bootloader v1.0 Upload to Flash 0x8002000", serial="LLM 003"
Found DFU: [1eaf:0003] ver=0201, devnum=7, cfg=1, intf=0, path="20-2", alt=1, name="STM32duino bootloader v1.0 Upload to Flash 0x8005000", serial="LLM 003"
Found DFU: [1eaf:0003] ver=0201, devnum=7, cfg=1, intf=0, path="20-2", alt=0, name="STM32duino bootloader v1.0 ERROR. Upload to RAM not supported.", serial="LLM 003"
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

dfu-util: Invalid DFU suffix signature
dfu-util: A valid DFU suffix will be required in a future dfu-util release!!!
Deducing device DFU version from functional descriptor length
dfu-util: More than one DFU capable USB device found! Try `--list' and specify the serial number or disconnect all but one device


ag123
Tue May 23, 2017 10:27 am
@JohnO,
you have another device that’s dfu capable hence the message, add the option -d 1eaf:0003 in the last line which installs the sketch itself
#!/bin/bash
dfu-util -l
dfu-util -d 1eaf:0003 -a 2 -R -D $*

RogerClark
Tue May 23, 2017 10:29 am
Windows 7 sometimes has this problem

The thing is…

Serial.begin() is already called in boards_setup.cpp in board_setup_usb() which is called from boards.cpp in init();

So if I have

void setup() {
// put your setup code here, to run once:
Serial.end();
delay(1000);
Serial.begin();
}
int c=0;
void loop() {
// put your main code here, to run repeatedly:
Serial.println(c++);
delay(500);
}


ag123
Tue May 23, 2017 10:38 am
@roger
i’d think it is ‘simplier’ to leave USBSerial.begin() in the libmaple core initialization codes.
the reason is that a lot of arduino sketches expect Serial to be ‘there’ and we’d likely get more ‘complaints’ about a non-functional Serial.

using that ‘flag’ sounds like an interesting solution. but i’m half wondering if in this case, the second Serial.begin() that’s started by the sketch in this particular case actually initialise the usb-serial interface! i.e. the first initialization failed. it seem there might be some other possibilities, e.g. between USBSerial.begin() to the 2nd Serial.begin(), a time out of some kind occurred if a delay is inserted before the second Serial.begin(), but i’m not sure though :?

i may spend a little time playing with usb.end(); usb_reset() /* i.e. pulling D+/D- low for 10ms */; usb_something_else.begin()
i think that’s a feasible way to implement a multi-function usb device.
usb serial should stay there as it is very useful to have a serial usb right at the start, the sketch can always ‘warp’ into another usb device in its code e.g. the sketch can ‘listen on usb-serial’ and then end usb-serial, do a usb reset, and initialise as usb something else. this would pave the way for a ‘multi-function’ usb device, i.e. usb-serial is always a default mode to listen to ‘commands’
just 2 cents ;)


JohnO
Tue May 23, 2017 10:40 am
ag123 wrote:@JohnO,
you have another device that’s dfu capable hence the message, add the option -d 1eaf:0003 in the last line which installs the sketch itself
#!/bin/bash
dfu-util -l
dfu-util -d 1eaf:0003 -a 2 -R -D $*

hanyazou
Tue May 23, 2017 12:16 pm
JohnO wrote:
@hanyazou Does your bootloader still have the Boot0 option to pull high during the fast flashes to enter perpetual bootloader?
My BP has a soft pulldown on Boot0 and I don’t seem able to pull it high to trigger perpetual bootloader mode.

JohnO
Tue May 23, 2017 2:23 pm
The “long” delay @hanyazou bootloader doesn’t appear to be required.

The enhanced @hanyazou bootloader together with the script amendments appears to do it all except the for the Serial.begin issue as explained by @Roger.


RogerClark
Tue May 23, 2017 9:53 pm
if you need the perpetual bootloader for uploads to work on your system, there is a way system where a magic number is put into a BKP register ( NV RAM) just prior to the sketch when reboot for upload is requested via serial.

From what I recall, I think I added the BKP register checking into the bootloader, but I didnt put the code in the core to set the value.

So you could try modifying the core to set the reg.

Edit.

Re-reading about this problem, locking the bootloader into perpetual mode via that flag sounds like ot would only partially fix the problem.


hanyazou
Tue May 23, 2017 10:01 pm
Why it cause problem when you call Serial.begin() twice with some delay() :| ?

RogerClark
Tue May 23, 2017 10:20 pm
hanyazou wrote:Why it cause problem when you call Serial.begin() twice with some delay() :| ?

hanyazou
Tue May 23, 2017 11:00 pm
I could reproduce the error with this modification.

void setup() {
delay(500);
- Serial.begin(9600);
+ Serial.begin();
while (!Serial);
Serial.println("Hello!");


RogerClark
Tue May 23, 2017 11:37 pm
hanyazou wrote:I could reproduce the error with this modification.

void setup() {
delay(500);
- Serial.begin(9600);
+ Serial.begin();
while (!Serial);
Serial.println("Hello!");


ag123
Wed May 24, 2017 3:24 am
i think it may be true that this is reproducible, my thoughts are that to diagnose this, it would be necessary to become familiar with the USB and USB CDC device class specifications. i’m not too sure if under certain conditions the host (i.e. PC / O/S etc) may end up in a *time out* due to an excessive delay.
the USB states and state transitions are rather complicated, among the states are a ‘stall’ state. once the usb host gets into the ‘stall’ state, i think it may stop sending responses to the device.

i tend to be able to reproduce this if i insert a delay in excess of 450ms before the Serial.begin() gets called. I’m not too sure why after Serial.begin() is called, it can tolerate a delay of 1000ms, i’ve yet to try further delays after the (second) Serial.begin()
http://www.stm32duino.com/viewtopic.php … =30#p28483

in the mean time, rather than trying to chase down the issue, my thoughts are that to avoid possible issues, call Serial.begin() as soon as Setup() starts.

The other test i’m yet to do and confirm is can we simply skip this Serial.begin() in the sketch as it has after all been called prior during the initialization stages even before it reaches main(). I’m not too sure if by virtue of an accident of timing, the 2nd Serial.begin() actually initialise the usb. this seem unlikely nevertheless. My thoughts are that the 2nd Serial.begin() simply re-initialise USB.

this may be quite involved to troubleshoot short of using things like logic analyzers and protocol analysers to examine the frame interchanges. most of us may not have those equipment and may need to improvise from other means to troubleshoot it.

i’m thinking if somehow we can use say an stm32f407 as a protocol analyser since it has 2 usb and has both otg and device mode. But still nevertheless, this won’t be easy as it would at least need to write the ‘sketch’ / s/w to do that.

just 2 cents


ag123
Wed May 24, 2017 3:53 am
hi all,

kindly note that i’ve submitted a PR for hanyazou’s and danieleff’s fixes for inserting a short delay just after flashing the sketch
http://www.stm32duino.com/viewtopic.php … 107#p28441
http://www.stm32duino.com/viewtopic.php … =10#p28452

kindly comment directly on github in the pull request with your feedback
>>> https://github.com/rogerclarkmelbourne/ … 2/pull/292


hanyazou
Wed May 24, 2017 1:18 pm
RogerClark wrote:hanyazou wrote:I could reproduce the error with this modification.

void setup() {
delay(500);
- Serial.begin(9600);
+ Serial.begin();
while (!Serial);
Serial.println("Hello!");


RogerClark
Wed May 24, 2017 9:39 pm
The flag should really be a boolean not an int

( the compiler may make it into an int, but its still best if its coded as a boolean. )

I will update the repo


hanyazou
Wed May 24, 2017 10:05 pm
Sorry! My patch looks not correct. The initial value and logic are odd though I tested my patch and it worked.

This patch works well. (but initial value is wrong.)
USBSerial::USBSerial(void) : running(1) {
#if !BOARD_HAVE_SERIALUSB
ASSERT(0);
#endif
}

void USBSerial::begin(void) {
if (running)
return;
running = 1;
#if BOARD_HAVE_SERIALUSB
usb_cdcacm_enable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT);
usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, rxHook);
usb_cdcacm_set_hooks(USB_CDCACM_HOOK_IFACE_SETUP, ifaceSetupHook);
#endif
}


RogerClark
Thu May 25, 2017 11:06 am
@hanyazou

Yes.

I noticed that something strange is happening

I put in some code to set a variable _hasBegun = true; in USBSerial::begin()

void USBSerial::begin(void) {
#if BOARD_HAVE_SERIALUSB
if (_hasBegun==true)
{
return;
}
usb_cdcacm_enable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT);
usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, rxHook);
usb_cdcacm_set_hooks(USB_CDCACM_HOOK_IFACE_SETUP, ifaceSetupHook);
_hasBegun=true;
#endif
}


hanyazou
Thu May 25, 2017 12:46 pm
I’ve sent PR for the bootloader.
https://github.com/rogerclarkmelbourne/ … er/pull/22

hanyazou
Sat May 27, 2017 3:49 am
RogerClark wrote:@hanyazou
I know the code is run really early in the init, but I”m not sure how the variable could be cleared, or perhaps its not getting set.
Perhaps making it static may help, as there is only one USB device on the F1

ag123
Sun May 28, 2017 8:41 am
calling codes directly in main() which isn’t board specific is not a good idea, as you would likely run into a different board that perhaps runs a differently named class that initialize SerialUSB e.g. in the F4 core it would be named SerialUSB rather than Serial
e.g. in the F4 (black/generic) branch that’s currently in development on steve’s repository, here is how init() is written, SerialUSB.begin() is run just before exiting from init()
https://github.com/stevstrong/Arduino_S … boards.cpp

my guess is we could actually call init() from main, just that there is a catch. the hardware initializations would not have happened until main() is entered and then main() calls init(). it could lead to unpredictable behaviour say if an interrupt happens prior to reaching there.

——- stm32f1duino bootstrap ———–
there are things that run before main() executes, this is how it works
in the variant’s folder e.g. STM32F1/variants/maple_mini/wirish there is start.S and start_c.c, the call graph starts as
start.s -> start_c() -> __libc_init_array();
__libc_init_array() is part of newlib which looks like this
https://github.com/eblot/newlib/blob/ma … isc/init.c
/* Iterate over all the init routines. */
void
__libc_init_array (void)
{
size_t count;
size_t i;

count = __preinit_array_end - __preinit_array_start;
for (i = 0; i < count; i++)
__preinit_array_start[i] (); //*********

_init ();

count = __init_array_end - __init_array_start;
for (i = 0; i < count; i++)
__init_array_start[i] ();
}


ag123
Sun May 28, 2017 9:31 am
there are some discussions about some variables needing to be declared ‘volatile’ or otherwise the compiler may ‘optimise away’ some codes, i’d guess we may need to dig deeper into the usb codes if indeed we suspect it is related to those ‘volatile’ declarations.

i think this recent fix by edogaldo for the ringbuffer is committed in the recent updates on master branch
http://www.stm32duino.com/viewtopic.php?f=3&t=2091
if USB serial uses the ringbuffer, perhaps it may have resolved, alleviated the issues?
:?


RogerClark
Sun May 28, 2017 9:50 am
I guess its worth a try declaring the flag as volatile, but I can’t see how that would fix it.

The USB code change to volatile is probably needed because its changed in an interrupt, but I’m not sure if the initialisation code is via an interrupt.

The F1 only has 1 USB interface, so the variable could be declared as static, but that solution would not work for the F4 as it has 2 USB posts


ag123
Sun May 28, 2017 9:53 am
i read somewhere that ‘volatile’ is to tell the compiler/cpu to read that value from memory/gpio rather than perhaps take the value from cache
i.e. the variable is deemed ‘volatile’ if the value can change even if the cpu itself ‘did nothing’. this would be true for gpio registers
but i’ve not dug deeper into the usb codes yet

i could imagine that if perhaps there are 2 statements
a = gpio_register;
b = gpio_register;
the compiler may read gpio_register and simply use cpu registers to update a and b. declaring gpio_register volatile i’d guess would make it always read from the memory location


hanyazou
Sun May 28, 2017 10:05 am
ag123 wrote:
——- stm32f1duino bootstrap ———–
there are things that run before main() executes, this is how it works
in the variant’s folder e.g. STM32F1/variants/maple_mini/wirish there is start.S and start_c.c, the call graph starts as
start.s -> start_c() -> __libc_init_array();

ag123
Sun May 28, 2017 10:07 am
as i’ve not gone in and examine the usb codes, i couldn’t tell if it is indeed the cause. but based on the analysis of the boot sequence
init() is not really different from main(), they are plain c functions

i’ve been toying with the idea that we call init(), setup() and loop() in main()
main() {
init();
setup();
while(1)
loop();
}


hanyazou
Sun May 28, 2017 10:09 am
I think both init() and ctors are called from __libc_init_array(). So ‘volatile’ does not matter.
You can’t call Serial.begin() in Init() because init() should be called brefore ctors.

hanyazou
Sun May 28, 2017 10:12 am
ag123 wrote:as i’ve not gone in and examine the usb codes, i couldn’t tell if it is indeed the cause. but based on the analysis of the boot sequence
init() is not really different from main(), they are plain c functions
[/code]

i think this is cleaner and easier to read


ag123
Sun May 28, 2017 10:14 am
i don’t think it matters as if you trace the codes e.g. using debug, those are basically common c functions, i.e. both init() and main();
but the usb codes and usb itself is rather complex and it would likely take some time to analyse and determine the root cause of issues

note that the *specai statement* ‘constructor’ is not the normal c++ constructors, they are c function hooks so that __libc_init_array() can call them.
in terms of static allocation, some of the global memory setups e.g. for global variables and static variables are done in start_c() itself
there could be a case in which c++ constructors uses the same __libc_init_array() mechanism, but i’m yet to examine it in detail, even then they are calling different functions possibly non-overlapping

alternatively there is actually a different hook
void _init () {}


hanyazou
Sun May 28, 2017 11:38 am
ag123 wrote:
as to the usb initialization, static object constructor. my thoughts are that one way to ‘fix it’ is that the usb class’s construction should not deal with hardware but simply initialize its own instance and global variables. by not touching hardware, it would not be caught in a situation e.g. that the interrupt vector address is changed.

ag123
Sun May 28, 2017 11:49 am
in this case it seem to be the double initialization UsbSerial.begin() that’s causing the trouble. would it help if we use a singleton pattern? e.g.
class UsbSerial {
public:
static UsbSerial* getInstance() {
static UsbSerial static_usbserial;
return &static_usbserial;
}
}

RogerClark
Sun May 28, 2017 11:58 am
I added the code to call USB Serial.Begin() without realising that there could be potential problems because of the whole init process, but strangely it does work, and the USB seeial is initialised OK.

The singleton method relies on a static property in the class, but as all we need to record is whether the USB Serial Begin has been called, cant we just make the _hasBegun property static?


ag123
Sun May 28, 2017 12:01 pm
it seemed this isn’t really about init() itself this time round, rather the *constructor* for UsbSerial is called *twice*, and create goofy scenarios.
what seemed necessary is some kind of ‘singleton’ codes so that there is only 1 instance and that we won’t be calling UsbSerial’s constructor twice

or perhaps if that 2nd init after all initialised things to work ok. we’d leave it after all. perhaps the ‘accident’ is that there is only one piece of usb hardware so if u initialise it again it is still the same :lol:

just 2 cents ;)


hanyazou
Sun May 28, 2017 12:16 pm
RogerClark wrote: cant we just make the _hasBegun property static?

Rick Kimball
Sun May 28, 2017 3:37 pm
Wasn’t the initial reason for the automatic Serial.begin() call because of a request from @jcw ? It seems like he has abandoned the use of Native USB, http://jeelabs.org/article/1708a/ and is using FTDI chips on a board he sells. He agreed with me during the original discussions that native USB is tedious to use.

I don’t really like that the Native USB is being instantiated without me (the user) requesting it. I dislike the 3 second delay when you configure your board to use the stm32duino bootloader. I would rather decide if and when I use the native serial. There is something about having something forced on me that just bothers me.

I can see the point of automatically configuring the native USB if you are using the bootloader. Otherwise you would have to press reset each time you upload.

However, I don’t see the point of automatically calling Serial.begin() if your upload method is set to Serial, STLink or BMP. In my opinion, It shouldn’t be called unless the user calls it. Calling it automatically eats up CPU to handle the USB heartbeat IRQ that i might want to use for other things. It delays my code from starting immediately at reset. It chews up flash code space that is never going to be called if I’m not using it.

FWIW: I’d like to see a optional native usb that doesn’t have the hokey in-stream parsing for the magic reset string. It would be a lot cleaner and probably smaller as all it would be doing is acting like a CDC ACM device.

With all that said, whatever is the final decision I can live with what happens. I’ll just ifdef out the stuff I don’t like and move on.


RogerClark
Sun May 28, 2017 10:03 pm
Rick,

I dont think USB Serial is enabled at all if you upload via Serial.

It is still enabled for STLink, as the STLink dongles dont have the built in serial that the nucleo boards version contains.

I cant remember what the current config is for the BMP, but USB serial could be disabled on the BMP as it also has its own serial.

The reason I added it for bootloader uploads, was because people complained that they could not upload automatically after installing a Blink sketch.

Its just the OP who seems to have a problem with the current situation, as they are calling Serial.begin again after delaying for 1 second.
calling Serial.begin at the top of setup() does not cause any problems – however I agree it should cause problems as the usb subsystem is being init’ed twice

So I think the static var is probably the best work around to mask that Serial.begin() has already been called in the init ( for some configurations)

The only potential problem with the static var would be for multiple instances of the USB Serial class, but we may be able to work around this ,by using bit fields in the static var to indicate the USB Serial instance number.
And on the F1 there is only one instance anyway.


danieleff
Mon May 29, 2017 6:29 am
hanyazou wrote:
Please note that the constructor of the Serial object does not touch the USB serial HW.
Currently, in my assumption, it goes like below:

0. start_c() called from start.S
1. __libc_init_array() called
2. init() called
3. board_setup_usb() called
4. Serial.begin() called
_hadBegun = true and the serial HW will be initialized.
5. the constructor, ‘USBSerial::USBSerial(void) : _hasBegun(false)’ called from __libc_init_array()
_hasBegun = false
6. main() called
7. setup() called
8. 2nd Serial.begin() called
This overwrite USB HW registers because _hadBegun == false.

The problem is that we call the Serial.begin() before the constructor of the Serial object is called.


ag123
Mon May 29, 2017 7:15 am
hi daniel,
__libc_init_array() is actually explicitly called in the startup codes start_c();
this runs the special premain() codes
__attribute__(( constructor (101))) void premain() {
init();
}

danieleff
Mon May 29, 2017 7:41 am
Wow that is a weird design to have init function called like it was a constructor.

jcw
Mon May 29, 2017 1:11 pm
(Yes master? Genie pops out of the bottle…)

As far as I can remember, the problem I was trying to solve back then is how to have a USB boot loader work together with a sketch. Since the boot loader needs to initialise and enumerate the USB hardware, I think the issue was to try and avoid re-initialising USB a second time in the sketch, as that would cause re-enumeration (i.e. breaking and restoring the serial connection) in “setup()”.

I’ve not continued on this path, but for anyone interested in this code – the latest version should be available on GitHub, see https://github.com/jeelabs/embello/tree … s/usbserup


hanyazou
Mon May 29, 2017 3:54 pm
danieleff wrote:
Did you step through with a debugger?
__libc_init_array() is called both in 1. and 5. steps?

ag123
Mon May 29, 2017 6:47 pm
@hanyazou

you are correct about your evaluations about the static class initializations
http://www.stm32duino.com/viewtopic.php … 132#p28861

it would seem the hardware initializations needs to be done in 2 parts those parts that the static constructors depend on needs to be called before the static object constructors

then there are hardware initializations that depend on the static objects e.g. USBSerial class/object. this would need to be called *after* the static constructors initializations are complete.

this could be for instance be in main() before setup().

however, hardware initializations tend to be board and mcu specific e.g. the usb controller on f1 and f4 are different, this would mean calling different functions deep down the call stack. hence in this case, it would be better if a second init() is created but this 2nd init lives in the board specific files. there could possibly be #includes in the board/variant files so that common initializations for a same family e.g. stm32f1 could be called in that common file.


hanyazou
Fri Jun 02, 2017 9:49 pm
I’d like to send PR of fix this USB initialization problem.

I’ve added init_2nd() and board_setup_usb_2nd() like below,

diff --git a/STM32F1/cores/maple/boards_private.h b/STM32F1/cores/maple/boards_private.h
index 49867ca..690577a 100644
--- a/STM32F1/cores/maple/boards_private.h
+++ b/STM32F1/cores/maple/boards_private.h
@@ -63,6 +63,7 @@ namespace wirish {
void board_setup_clock_prescalers(void);
void board_setup_gpio(void);
void board_setup_usb(void);
+ void board_setup_usb_2nd(void);
void series_init(void);

}
diff --git a/STM32F1/cores/maple/main.cpp b/STM32F1/cores/maple/main.cpp
index 3d78443..73f6f14 100644
--- a/STM32F1/cores/maple/main.cpp
+++ b/STM32F1/cores/maple/main.cpp
@@ -27,6 +27,7 @@
extern void setup(void);
extern void loop(void);
extern void init(void);
+extern void init_2nd(void);

// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated objects that need libmaple may fail.
@@ -35,6 +36,7 @@ extern void init(void);
}

int main(void) {
+ init_2nd(); // board initialization using statically allocated objects
setup();

while (1) {
diff --git a/STM32F1/cores/maple/usb_serial.cpp b/STM32F1/cores/maple/usb_serial.cpp
index 5eaf70e..dc86da7 100644
--- a/STM32F1/cores/maple/usb_serial.cpp
+++ b/STM32F1/cores/maple/usb_serial.cpp
@@ -55,13 +55,16 @@ static void ifaceSetupHook(unsigned, void*);

#define USB_TIMEOUT 50

-USBSerial::USBSerial(void) {
+USBSerial::USBSerial(void) : _hasBegun(false) {
#if !BOARD_HAVE_SERIALUSB
ASSERT(0);
#endif
}

void USBSerial::begin(void) {
+ if (_hasBegun)
+ return;
+ _hasBegun = true;
#if BOARD_HAVE_SERIALUSB
usb_cdcacm_enable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT);
usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, rxHook);
@@ -90,6 +93,7 @@ void USBSerial::end(void) {
usb_cdcacm_disable(BOARD_USB_DISC_DEV, BOARD_USB_DISC_BIT);
usb_cdcacm_remove_hooks(USB_CDCACM_HOOK_RX | USB_CDCACM_HOOK_IFACE_SETUP);
#endif
+ _hasBegun = false;
}

size_t USBSerial::write(uint8 ch) {
diff --git a/STM32F1/cores/maple/usb_serial.h b/STM32F1/cores/maple/usb_serial.h
index 96bbefc..cf66347 100644
--- a/STM32F1/cores/maple/usb_serial.h
+++ b/STM32F1/cores/maple/usb_serial.h
@@ -71,6 +71,9 @@ public:
uint8 getDTR();
uint8 isConnected();
uint8 pending();
+
+protected:
+ bool _hasBegun;
};

#ifdef SERIAL_USB
diff --git a/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp b/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp
index 36fcb3e..a6acbb5 100644
--- a/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp
+++ b/STM32F1/variants/generic_stm32f103c/wirish/boards.cpp
@@ -75,6 +75,10 @@ void init(void) {
boardInit();^M
}^M
^M
+void init_2nd(void) {^M
+ wirish::priv::board_setup_usb_2nd();^M
+}^M
+^M
/* Provide a default no-op boardInit(). */^M
__weak void boardInit(void) {^M
}^M
diff --git a/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp b/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp
index 5516282..b1e2c34 100644
--- a/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp
+++ b/STM32F1/variants/generic_stm32f103c/wirish/boards_setup.cpp
@@ -94,10 +94,16 @@ namespace wirish {
for(volatile unsigned int i=0;i<512;i++);// Only small delay seems to be needed, and USB pins will get configured in Serial.begin^M
gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_INPUT_FLOATING);^M
#endif ^M
- Serial.begin();// Roger Clark. Changed SerialUSB to Serial for Arduino sketch compatibility^M
#endif^M
}^M
^M
+ __weak void board_setup_usb_2nd(void) {^M
+#ifdef SERIAL_USB^M
+ // Roger Clark. Changed SerialUSB to Serial for Arduino sketch compatibility^M
+ Serial.begin();^M
+#endif^M
+ }^M
+^M
__weak void series_init(void) {^M
// Initialize AFIO here, too, so peripheral remaps and external^M
// interrupts work out of the box.^M


RogerClark
Fri Jun 02, 2017 9:52 pm
please do this as a PR, even if only for the BluePill ( generic stm32f103c ) , then other people can test it for themselves

hanyazou
Fri Jun 02, 2017 10:04 pm
Do you mean you think the latter simple patch is better? I must change all of STM32F1/variants/*/wirish/ if I change main() in STM32F1/cores/maple/main.c.

RogerClark
Fri Jun 02, 2017 10:32 pm
I do not know what chance you change has to be accepted by the community.

But if you submit a PR for one board e.g. The BluePill, it will allow the community to test it, and if there is an overwhelming majority in favour of the change it may become part of the core.

Although I host the LibMaple core, ultimately it’s open source and if it changes in ways people don’t like, they will just fork the repo and the community will use a different version without those changes.

So, changes which help a minority of users but cause problems for the majority of users, never get accepted.


hanyazou
Fri Jun 02, 2017 11:54 pm
RogerClark wrote:I do not know what chance you change has to be accepted by the community.

But if you submit a PR for one board e.g. The BluePill, it will allow the community to test it, and if there is an overwhelming majority in favour of the change it may become part of the core.

Although I host the LibMaple core, ultimately it’s open source and if it changes in ways people don’t like, they will just fork the repo and the community will use a different version without those changes.

So, changes which help a minority of users but cause problems for the majority of users, never get accepted.


RogerClark
Sat Jun 03, 2017 12:46 am
hanyazou wrote:

I know. I just wanted to hear a comment of you who is a member of the community. :)


ag123
Sat Jun 03, 2017 7:55 am
i think the fix is good :)
this ‘discovery’ about c++ global or static objects is an ‘enlightenment’ it never occurs to me that static class initialization has to do with a single c function __libc_init_array(), i.e. c++ is designed for ‘everything to happen in main()’ not before it. c++ is designed for ‘system programming’ but i’d guess the designers didn’t managed to solve the problem if there is only an egg (writing the o/s) without the chicken (the o/s itself) :lol:

RogerClark
Tue Jun 06, 2017 10:28 pm
I’ve pulled the PR to fix this, and it works fine.

However I have noticed another existing bug.

I added 2 dummy functions for begin

//Roger Clark. Two new begin functions has been added so that normal Arduino Sketches that use Serial.begin(xxx) will compile.
void USBSerial::begin(unsigned long ignoreBaud)
{
volatile unsigned long removeCompilerWarningsIgnoreBaud=ignoreBaud;

ignoreBaud=removeCompilerWarningsIgnoreBaud;
}
void USBSerial::begin(unsigned long ignoreBaud, uint8_t ignore)
{
volatile unsigned long removeCompilerWarningsIgnoreBaud=ignoreBaud;
volatile uint8_t removeCompilerWarningsIgnore=ignore;

ignoreBaud=removeCompilerWarningsIgnoreBaud;
ignore=removeCompilerWarningsIgnore;
}


RogerClark
Wed Jun 07, 2017 4:04 am
I updated the repo with a fix for the issue I outlined above…

But I”ve found another issue which seems to affect the Maple mini and would also effect the BluePill

If I call Serial.end(); and then Serial.begin() the USB no longer works.

This seems to be because the code in usb_cdcacm_enable does not really reset the USB, it just “presents” the device to the host

void usb_cdcacm_enable(gpio_dev *disc_dev, uint8 disc_bit) {
/* Present ourselves to the host. Writing 0 to "disc" pin must
* pull USB_DP pin up while leaving USB_DM pulled down by the
* transceiver. See USB 2.0 spec, section 7.1.7.3. */
gpio_set_mode(disc_dev, disc_bit, GPIO_OUTPUT_PP);
gpio_write_bit(disc_dev, disc_bit, 0);

/* Initialize the USB peripheral. */
usb_init_usblib(USBLIB, ep_int_in, ep_int_out);
}


RogerClark
Wed Jun 07, 2017 6:54 am
I’ve just noticed that in USBSerial::end it does call usb_cdcacm_disable, which

does set the usb disc bit

gpio_write_bit(disc_dev, disc_bit, 1);


Leave a Reply

Your email address will not be published. Required fields are marked *