The target hardware is this here: https://www.tindie.com/products/onehors … out-board/
The code is here: https://github.com/GrumpyOldPizza/arduino-STM32L4
Ok, what is special about it ?
The concept was to come up with an Arduino Zero compatible pinout and software layer. There is a 16MB NOR FLASH on the board which is acessable from a sketch as normal local file system, while at the same time it will show up on the host via USB/MSC. Nice for logging to say at least. Overall low-power was the main motivator.
Something that always bothered me about Arduino is the idea of blocking, synchronous io. Most of the things I deal with really shine with asynchronous io. So this port added consistently asynchronous io. For I2C/Wire it looks like this here:
bool transfer(uint8_t address, const uint8_t *txBuffer, size_t txSize, uint8_t *rxBuffer, size_t rxSize, bool stopBit, void(*callback)(uint8_t));
bool done(void);
uint8_t status(void);
Where are the CMSIS / Drivers files from? The STM32 Cube ?
Did you write all of the mid layer code to interface with the CMSIS
There is a parallel project that @sheepdoll and @vassilis are working on which uses the STM32 Cube to build a new “core” which uses the HAL
This core would support the STM32L4, (if they exported the Cube files for that target)
But at the moment it only has a USB CDC Serial device, and it will operate like libmaple, using the bootloader to upload via DFU before it switches to using the Serial USB CDC device built into the sketch
Where are the CMSIS / Drivers files from? The STM32 Cube ?
Did you write all of the mid layer code to interface with the CMSIS
There is a parallel project that @sheepdoll and @vassilis are working on which uses the STM32 Cube to build a new “core” which uses the HAL
This core would support the STM32L4, (if they exported the Cube files for that target)
I thought you were using “mass storage” mode to upload ?
I thought you were using “mass storage” mode to upload ?
I’m not sure where I got the idea you were using mass storage, I think it must have been another project ![]()
I think the new BBC Micro Bit uses that method, but it uses a completely different processor.
And I think it uses a separate processor for upload to the main processor
It would be possible to write a bootloader that enumerated as a Mass storage device, which wrote straight into flash, and then jumped to the sketch start address, and I guess this removes the need for a DFU driver.
Its a shame there isn’t a default Serial CDC VID PID that can be uses, as most systems have this sort of driver as part of the OS (thats what libmaple uses, but it has to enumate as a leaflabs device, which means we have to fool windows into loading the correct / built in driver )
I’m not sure where I got the idea you were using mass storage, I think it must have been another project ![]()
I think the new BBC Micro Bit uses that method, but it uses a completely different processor.
And I think it uses a separate processor for upload to the main processor
It would be possible to write a bootloader that enumerated as a Mass storage device, which wrote straight into flash, and then jumped to the sketch start address, and I guess this removes the need for a DFU driver.
…
The code is here: https://github.com/GrumpyOldPizza/arduino-STM32L4
Thanx for checking. Yes, I need to get some of the warnings figured out. The system code should be fairly clean. I moved late from gcc 4.9 to 4.8.3, so some things need cleanup. Did you see anything worrying ?
I did notice that the generated binary is rather large, about ~45k. This was using the ASCIITable example. On a generic f103cx board it is only about ~14k for the maple version. Granted it probably doesn’t matter with a board that has 512K of flash.
I had not checked into the size. There is are couple of reasons. One is that the image always carries the full USB stack, including USB/MSC and the FAT backend along with it. This will even worse when a gdbstub and an RTOS are added. But as you pointed out, it should not matter that much with 512k. An alternate solution is to keep some kind of boot image constantly in the flash that contains all of those functions, but does not get reflashed every time.
I noticed that you turned on the -mslow-flash-data option. I thought those F4 chips had that ART flash accelerator that effectively makes flash zero wait state? Is there any advantage to using the movw/movt style of ldr loading compared to using the typical loading from PC relative constants?
Ah, yes the effects of marketing
ART is really just a code/data cache. On STM32L4 it’s 1024/256 bytes. Running at 80Hz one gets hit with 4 wait states with a FLASH access that is not in the cache. ART has a prefetcher that sucks up a lot of power, but does not seem to be terribly efficient. So without that “-mslow-flash-data” option, gcc places all literals at the end of a function (or sometimes groups of functions). So most of those literal fetches will cause a miss on the data cache part. The prefetcher does not prefetch data, only instructions. So for every 64 bit of literal data, you will take the 4 cycle hit. On the other hand if the compiler emits movw/movt the literals are part of the intruction stream and can be efficiently prefetched. I wish I had written down numbers when I did the analysis.
N.b. STM32F4 is different. STM32F446 for example has the same cache sizes, but 128 bit wide accesses, and at 80Mhz only 2 wait states (at 180MHz still 5). So the perf pattern there is different.
"/home/kimballr/.arduino15/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi-g++" -mcpu=cortex-m4 -mthumb -c -g -Os -Wall -std=gnu++11 -ffunction-sections -fdata-sections -fno-threadsafe-statics -nostdlib --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD -DF_CPU=80000000L -DARDUINO=10609 -DARDUINO_STM32L4_DRAGONFLY -DARDUINO_ARCH_ARDUINO-STM32L4 -DSTM32L476xx -D__FPU_PRESENT=1 -march=armv7e-m -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mabi=aapcs -mslow-flash-data "-I/home/kimballr/Arduino/hardware/grumpy/arduino-STM32L4/system/libstm32l4_dragonfly/CMSIS/Include" "-I/home/kimballr/Arduino/hardware/grumpy/arduino-STM32L4/system/libstm32l4_dragonfly/CMSIS/Device/ST/STM32L4xx/Include" "-I/home/kimballr/Arduino/hardware/grumpy/arduino-STM32L4/system/libstm32l4_dragonfly/USB/HAL/Inc" "-I/home/kimballr/Arduino/hardware/grumpy/arduino-STM32L4/system/libstm32l4_dragonfly/USB/Core/Inc" "-I/home/kimballr/Arduino/hardware/grumpy/arduino-STM32L4/system/libstm32l4_dragonfly/USB/Class/CDC/Inc" "-I/home/kimballr/Arduino/hardware/grumpy/arduino-STM32L4/system/libstm32l4_dragonfly/USB/Class/MSC/Inc" "-I/home/kimballr/Arduino/hardware/grumpy/arduino-STM32L4/system/libstm32l4_dragonfly/USB" "-I/home/kimballr/Arduino/hardware/grumpy/arduino-STM32L4/system/libstm32l4_dragonfly" "-I/home/kimballr/Arduino/hardware/grumpy/arduino-STM32L4/cores/stm32l4" "-I/home/kimballr/Arduino/hardware/grumpy/arduino-STM32L4/variants/dragonfly" "/home/kimballr/Arduino/hardware/grumpy/arduino-STM32L4/cores/stm32l4/Uart.cpp" -o "/tmp/build9b48bf045704f942a14727407c65a0ba.tmp/core/Uart.cpp.o"
<command-line>:0:21: warning: ISO C99 requires whitespace after the macro name [enabled by default]@vassilis added USB Serial to the HAL MX the other day, but I have not had chance to test it or look at the binary size, but I think it may be bigger than 45k
Example:
https://github.com/GrumpyOldPizza/ardui … gpio.c#L44
Is this just to insure thread safety in some future release that supports an RTOS?
-rick
Must say I’m also impressed by the “under-promise, over-deliver” approach.
Example:
https://github.com/GrumpyOldPizza/ardui … gpio.c#L44
Is this just to insure thread safety in some future release that supports an RTOS?
@vassilis added USB Serial to the HAL MX the other day, but I have not had chance to test it or look at the binary size, but I think it may be bigger than 45k
@vassilis added USB Serial to the HAL MX the other day, but I have not had chance to test it or look at the binary size, but I think it may be bigger than 45k
You have the -nostdlib flag on the c compile flags. That is a ldflags argument. If I move it to ldflags in the platform.txt file, it starts complaining about missing functions … memcpy, _init, _libc_init_array .. etc ..
-rick
You have the -nostdlib flag on the c compile flags. That is a ldflags argument. If I move it to ldflags in the platform.txt file, it starts complaining about missing functions … memcpy, _init, _libc_init_array .. etc ..
-rick
memory-to-memory DMA vs library memcpy()
DUE 84MHz maple 72Mhz teensy 96MHz mbed LPC1768 96mhz
ZERO 48MHz CC3200 80MHz STM32L4 80MHz mbed MK64F 120 mhz
For the DUE DMA memory-to-memory transfer, we use the 32-byte FIFO channel 5
and ASAP_CFG. We compare the DMA times on the DUE,teensy, and maple with the
library memcpy() and memset() and with a for-loop (dst[i] = src[i]) using
1000 32-bit words. memcpy32() is the DMA version. The library memcpy()
uses an unrolled (64) loop of word load/store's. The teensy 3.* at 96MHz
has a max eDMA SRAM-to-SRAM speed of 192MBs (1536mbs).
Times are in microseconds
maple DUE teensy 3.1 mbed ZERO CC3200 STM32L4 MK64F
loop 269 132 95 94 9 217 461 26
memcpy32 93 31 23 27 9 43 31 69 35
memcpy 62 52 96 50 9 194 15 29 26
memset32 94 34 23 43 19
memset 38 41 51 24 6 12 16 17
DUEling memory copies:
In mem2mem2 we used an asynchronous DMA memory transfer of 1024 32-bit words,
starting the DMA version then starting the library memcpy. For the maple,
the library memcpy() completes first (64us), then the DMA finishes (122us)
with total elapsed time of 122us.
For the DUE, the DMA copy finishes first (34us), then the memcpy (80us),
with total elapsed time of 82us. Both src/dst pairs were in SRAM0.
With the memcpy() src/dst pairs in SRAM1, DMA took 33us, and the memcpy
took 60us, with elapsed time of 70us.
For the teensy 3.0, the DMA finishes first (27us), and then the memcpy (105us),
with total elapsed time of 107us. Teensy test used two different destination
buffers, but same source buffer (only 16KB RAM on 3.0). For teensy 3.1, DMA
finishes first (48us), then memcpy (65us), for total 66us.
If you run the “Blink” example off a battery (not via USB connector) the power consumption is now below 7mA (@ 80MHz). “maple” weighs in with about 48mA (@ 72MHz) in the same scenario, while Teensy 3.2 draws about 38mA (@96MHz).
Also added a clock selection menu, so that 80Mhz, 72MHz, 64MHz, 48MHz, 32MHz, 24MHz and 16MHz can be used.
Hopefully I can get my hands on some low power devices and test this core sooner or later
Hopefully I can get my hands on some low power devices and test this core sooner or later
There are mcu vendors who are happy with 500uA/MHz..
When your program has nothing to do, or nothing to do until the next interrupt, just
__WFI;
Sleeps the CPU until next interrupt, most often it’s the 1KHz systick used on most systems. But could be any interrupt.
When your program has nothing to do, or nothing to do until the next interrupt, just
__WFI;
Sleeps the CPU until next interrupt, most often it’s the 1KHz systick used on most systems. But could be any interrupt.
<…>
Interesting comments.
<…>
Are they trying to let an ISR use print()? I’ve never seen such done. Rule 1 in ISRs, you know.
Are they trying to let an ISR use print()? I’ve never seen such done. Rule 1 in ISRs, you know.
You could also do a for (i = 0 to infinity) in the ISR.
Crazy.
You could also do a for (i = 0 to infinity) in the ISR.
Crazy.
You could also do a for (i = 0 to infinity) in the ISR.
Crazy.
Breaks lots of things, calling libraries related to print from an ISR. Such as non-reentrant library code and hosing up the latency.
Arduino-land is the only place I’ve seen an attempt to do such, and it’s naive.
Breaks lots of things, calling libraries related to print from an ISR. Such as non-reentrant library code and hosing up the latency.
Arduino-land is the only place I’ve seen an attempt to do such, and it’s naive.
There’s a reason that it’s not ever done in real life.
/home/kimballr/Arduino/hardware/grumpy/STM32L4/cores/stm32l4/wiring.c: In function 'HardFault_Handler':
/home/kimballr/Arduino/hardware/grumpy/STM32L4/cores/stm32l4/wiring.c:34:2: warning: implicit declaration of function 'OTG_FS_IRQHandler' [-Wimplicit-function-declaration]
OTG_FS_IRQHandler();
^
/home/kimballr/Arduino/hardware/grumpy/STM32L4/cores/stm32l4/wiring.c: In function 'HardFault_Handler':
/home/kimballr/Arduino/hardware/grumpy/STM32L4/cores/stm32l4/wiring.c:34:2: warning: implicit declaration of function 'OTG_FS_IRQHandler' [-Wimplicit-function-declaration]
OTG_FS_IRQHandler();
^
You could also do a for (i = 0 to infinity) in the ISR.
Crazy.
<…>
Let’s go back as to why folks use Arduino. They have no clue, but want to get something done. They need to experiment and learn. You learn best from making mistakes.
<…>
Let’s go back as to why folks use Arduino. They have no clue, but want to get something done. They need to experiment and learn. You learn best from making mistakes.
Arduino is now her own being and is a product of the parents, teachers, environment, and her childhood friends. There are powerful commercial interests such as Intel pushing themselves in what has become an ever increasing numbers of suitors seeking her sole affection… but for now, she seems to just want to play the field and not settle down.
Of what I am certain is that the increasing commercialism will force the IDE to be more accomodating to flexibility. We only need to look at Linux to see what can evolve from a concept.
Ray
also, i have put this on a github page about stm32 external flash storage (just not sure if it’ll work)
in the linker script there needs to be:
EXTFLASH (rw) : ORIGIN = 0x<start address>, LENGTH = 0x<length>
in the MEMORY section, and the SECTIONS needs to have:
.external_flash : { *(.External_Flash*); } > EXTFLASH
now we can start to have fun with adding code to the qspi flash.
to make it easy, use this define in the sketch:
#define EXTERNAL_MEM __attribute__((section("External_Flash")))
and usage can look like this:
EXTERNAL_MEM void external_loop()
{
while (1)
{
//blink led forever
digitalWrite(13,LOW);
delay(500);
digitalWrite(13,HIGH);
delay(500);
}
}
I was expecting the super-capacitor pictured (I think thats what it was). Its no biggie that it wasn’t, but it did take a little shine off the product.
Unfortunately I am one of those with “no clue” with a full time job in another area. So time is an obstacle.
However I am not daunted by my lack of time.
I would like to know if there is a forum somewhere devoted to this device, and a quickstart guide or something.
I have used a teensy 3.1 and 3.2 as I have a few of those. But I suppose I’d like to get into it and get my project done… without having to stuff around with trial an error.
Raj
also, i have put this on a github page about stm32 external flash storage (just not sure if it’ll work)
in the linker script there needs to be:
EXTFLASH (rw) : ORIGIN = 0x<start address>, LENGTH = 0x<length>
in the MEMORY section, and the SECTIONS needs to have:
.external_flash : { *(.External_Flash*); } > EXTFLASH
now we can start to have fun with adding code to the qspi flash.
to make it easy, use this define in the sketch:
#define EXTERNAL_MEM __attribute__((section("External_Flash")))
and usage can look like this:
EXTERNAL_MEM void external_loop()
{
while (1)
{
//blink led forever
digitalWrite(13,LOW);
delay(500);
digitalWrite(13,HIGH);
delay(500);
}
}
I was expecting the super-capacitor pictured (I think thats what it was). Its no biggie that it wasn’t, but it did take a little shine off the product.
Unfortunately I am one of those with “no clue” with a full time job in another area. So time is an obstacle.
However I am not daunted by my lack of time.
I would like to know if there is a forum somewhere devoted to this device, and a quickstart guide or something.
I have used a teensy 3.1 and 3.2 as I have a few of those. But I suppose I’d like to get into it and get my project done… without having to stuff around with trial an error.
Raj
uThe QSPI flash is setup as a FAT file system, not as a flash extender. There are numerous reasons to do so. If the normal 512k flash runs out, one could always ask for a 1MB STM32L476 instead.
uThe QSPI flash is setup as a FAT file system, not as a flash extender. There are numerous reasons to do so. If the normal 512k flash runs out, one could always ask for a 1MB STM32L476 instead.
2: so basically you’re saying that the pebble smartwatches have much latency? i think not, they fit their purpose well, and use the same approach as i am trying to do. ![]()
here’s a document on that for stm32 devices having that feature (including the stm32l4)
http://www.st.com/content/ccc/resource/ … m=auto,100
you said the platform is open? if so, why not the bootloader? (just questioning)
you said the platform is open? if so, why not the bootloader? (just questioning)
you said the platform is open? if so, why not the bootloader? (just questioning)
you said the platform is open? if so, why not the bootloader? (just questioning)
but my plant on creating a watch based on the platform is still there
but my plant on creating a watch based on the platform is still there
The clock speed is low by comparison with modern ARM devices, as it only runs at 16MHz, but its got 32k RAM (in the QFAC version) which is more than the BluePill etc, and it has 256k flash ( in the QFAA and QFAC versions).
For anyone currently using AVR hardware, the nRF51 is a significantly better device.
In my experience, the low power consumption is also very good, i.e from memory the low power modes operate in the micro amps range.
Price is also good on the nRF51, probably as its now not the flagship device for Nordic, hence loads more Chinese manufacturers are switching to it instead of the CC2541.
So there are loads more hackable nRF51 devices coming into the market, which is great news for the Maker and Arduino community
The clock speed is low by comparison with modern ARM devices, as it only runs at 16MHz, but its got 32k RAM (in the QFAC version) which is more than the BluePill etc, and it has 256k flash ( in the QFAA and QFAC versions).
For anyone currently using AVR hardware, the nRF51 is a significantly better device.
In my experience, the low power consumption is also very good, i.e from memory the low power modes operate in the micro amps range.
Price is also good on the nRF51, probably as its now not the flagship device for Nordic, hence loads more Chinese manufacturers are switching to it instead of the CC2541.
So there are loads more hackable nRF51 devices coming into the market, which is great news for the Maker and Arduino community
It’s my understanding that for the M0 core in the nRF51 the Systick got not implemented. That would force you to use one of the RTC peripherals, clocked off 32768Hz. So a lot of the standard Cortex-M0 code will not work that easily. Bunch of details like this that derail you coming from other Cortex-M0 products.
Actually I want to run it from the 32khz crystal, as I want to run the whole device in its low power mode most of the time, and I think in that mode, it is actually running the whole processor from the 32khz crystal rather than the 16Mhz
Luckily most of the nRF51 devices I have, contain the 32Khz, as if they don’t then keeping time is a pain, as it requires constant recalibration of the 32kHz RC Osc against the 16Mhz main system clock, which entails the MCU waking up to calibrate its self every few seconds. (though this setting can be changed to shorter or longer durations)
I bought a small nRF51 module from a german vendor on eBay, and it arrived yesterday.
But I have not had time to even solder some tiny wires to it.
BTW. if you are playing with nRF52, I hear the first version of the device has a number of Errata in its silicon.
There are work-arounds for this, but its the reason why at the moment I only bought one nRF52, as I could not confirm the revision number ( as it is inside a metal enclosure on the PCB)
I bought a small nRF51 module from a german vendor on eBay, and it arrived yesterday.
But I have not had time to even solder some tiny wires to it.
BTW. if you are playing with nRF52, I hear the first version of the device has a number of Errata in its silicon.
There are work-arounds for this, but its the reason why at the moment I only bought one nRF52, as I could not confirm the revision number ( as it is inside a metal enclosure on the PCB)
I know there were work-arounds for most of the errata.
Not directly related but I also found out on the nRF51 that QFAA versions with revisions below H, will not work with V2.0.x of the S130 SoftDevice.
Which means I can’t use some of my old boards with SDK V11 or SDK V12. Consequentially I’m sticking with SDK10 for the foreseeable future.
I’m not entirely sure what changed in the silicon, but it must be something important if it prevents you using the latest 2 SDK revisions.
A lot of new clock frequencies have been added:
1MHz & 2MHz Range 2, LPrun
4MHz, 8MHZ, 16MHz & 24MHz Range 2
32MHz, 48MHz, 64MHz, 72MHz & 80MHz Range 1
If USB is connected that board will not go lower than 16MHz to keep USB working. There is a programmer added, which allows direct downloads via STLink, so that low power modes can be tested. I think 16Mhz is now at around 2.2mA for the infamous “Blink” example.
A new RTC class has been added. Essentially RTCZero compatible, but also allows control over synchronization with another time master, and fine calibration of the time.
Ah, and preliminary support for NUCLEO-L476 has been added.
(There is a lot of reorg going on for upcoming boards…)
Ignoring the potential fragility of this compact Nucleo board, I am very pleased for it. The combination of high performance, compact size, and low power consumption is required in many applications.
Cheers, Ollie
The ESD protection in the packaging was overwhelming. Now I am wondering, if any of you have damaged your board and how it happened?
…
Ignoring the potential fragility of this compact Nucleo board, I am very pleased for it. The combination of high performance, compact size, and low power consumption is required in many applications.
Cheers, Ollie
Cheers, Ollie
Cheers, Ollie
I have purchased a Nucleo-L476RG, and I’ve tried to unzip https://github.com/GrumpyOldPizza/arduino-STM32L4 in the hardware folder in my Arduino folder.
I am on MacOS 10.12.1 and Arduino 1.6.13, but, I can’t see anything on the board section.
Do you have any idea on how to fix this ?
Thanks
Also for NUCLEO-L476RG SDIO is exposed on the PC8/PC9/PC10/PC11/PC12/PD2 pins, and SDCARD via SPI on PC10/PC11/PC12/PD2.
The code will work with most breakout boards that have no pullups on CS/DAT3. SDIO is a tad fiddely, as cabling can have an adverse effect.
SPI gets around 2.3MB/sec, SDIO with default speed (read 24MHz) is at roughly 11MB/sec, and SDIO with high speed (read 48MHz) get about 22MB/sec. Write rates differ from card to card though. A class 10 card will not get more than 10MB/sec …
USB support is now configurable, so that either CDC or CDC+MSC (or none) can be selected.
– Thomas
First, thanks for yours jobs, It makes the stm32 comes in Arduino world!
here is the problem that i face:
Serial.print() is working well but Serial.read() did not return any response while i send out data
anyone can help pls, sorry for the stupid question
Could you, please, give the correct path to be added on Arduino Preferences?
Thanks a lot and ciao from Italy
Could you, please, give the correct path to be added on Arduino Preferences?
Thanks a lot and ciao from Italy
I’ve tried manual installation but no luck… (Arduino 1.8.0 on W10-64)
Best regards
Guido
I’ve tried manual installation but no luck… (Arduino 1.8.0 on W10-64)
Best regards
Guido
In which folder I have to extract your files?
Thanks
Guido
I’ve tried manual installation but no luck… (Arduino 1.8.0 on W10-64)
Best regards
Guido
I’ve tried manual installation but no luck… (Arduino 1.8.0 on W10-64)
Best regards
Guido
Thumbs UP!
Thanks a lot and ciao from Italy
Guido
it has less uA/mhz power consumption (320k), more sram and more flash (up to 1mb)
also, does anyone have an example on how to put the flash ic into XIP (or similar) mode, as the datasheet says it can, also provides some explaination, but i can’t figure it out at all..
anyhow, keep it up!
Can you elaborate on that? I would really like to work on the l476 platform, and I don’t mind giving away, say, the LCD. What adjustments would be required to use the STM32L476GDiscovery? Thank you
Can you elaborate on that? I would really like to work on the l476 platform, and I don’t mind giving away, say, the LCD. What adjustments would be required to use the STM32L476GDiscovery? Thank you
it has less uA/mhz power consumption (320k), more sram and more flash (up to 1mb)
also, does anyone have an example on how to put the flash ic into XIP (or similar) mode, as the datasheet says it can, also provides some explaination, but i can’t figure it out at all..
anyhow, keep it up!
Can you elaborate on that? I would really like to work on the l476 platform, and I don’t mind giving away, say, the LCD. What adjustments would be required to use the STM32L476GDiscovery? Thank you
Can you elaborate on that? I would really like to work on the l476 platform, and I don’t mind giving away, say, the LCD. What adjustments would be required to use the STM32L476GDiscovery? Thank you
Change the board.txt to upload with ST-link-V2 as hade to move the boot jumper to get DFU upload.
Now I only the Port name ex PC13 to led are there any plan to have port name and pin name as we have on F103 bluePill ?
I can wright a #define PC13 39 // PC13 är Led and soo on to get my old program to work.
If I whant more Analog in how to change the file variant.cpp for that ? Soo I get all 10 A/D that the hardware support.
Ex PA2 that have A/D but not configed
{ GPIOA, GPIO_PIN_MASK(GPIO_PIN_PA2), GPIO_PIN_PA2_TIM2_CH3, (PIN_ATTR_PWM | PIN_ATTR_EXTI | PIN_ATTR_WKUP4), PWM_INSTANCE_TIM2, PWM_CHANNEL_3, ADC_INPUT_NONE },
For PA4 that have A/D configed it is like this
{ GPIOA, GPIO_PIN_MASK(GPIO_PIN_PA4), GPIO_PIN_PA4, (PIN_ATTR_ADC | PIN_ATTR_DAC | PIN_ATTR_EXTI), PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_INPUT_9 },
Jonas
Change the board.txt to upload with ST-link-V2 as hade to move the boot jumper to get DFU upload.
Now I only the Port name ex PC13 to led are there any plan to have port name and pin name as we have on F103 bluePill ?
I can wright a #define PC13 39 // PC13 är Led and soo on to get my old program to work.
If I whant more Analog in how to change the file variant.cpp for that ? Soo I get all 10 A/D that the hardware support.
Ex PA2 that have A/D but not configed
{ GPIOA, GPIO_PIN_MASK(GPIO_PIN_PA2), GPIO_PIN_PA2_TIM2_CH3, (PIN_ATTR_PWM | PIN_ATTR_EXTI | PIN_ATTR_WKUP4), PWM_INSTANCE_TIM2, PWM_CHANNEL_3, ADC_INPUT_NONE },
For PA4 that have A/D configed it is like this
{ GPIOA, GPIO_PIN_MASK(GPIO_PIN_PA4), GPIO_PIN_PA4, (PIN_ATTR_ADC | PIN_ATTR_DAC | PIN_ATTR_EXTI), PWM_INSTANCE_NONE, PWM_CHANNEL_NONE, ADC_INPUT_9 },
Jonas
My DFU problem may can be that the bluepill hardware are diffrent. I did only get the ST Dfu dected by the computer so went to ST-link.
Dont get usbserial to work but i think that is only computer problem as serial1 work over Fdi adaptern.
It is some usb driver thats are missing or wrong.
Jonas
My DFU problem may can be that the bluepill hardware are diffrent. I did only get the ST Dfu dected by the computer so went to ST-link.
Dont get usbserial to work but i think that is only computer problem as serial1 work over Fdi adaptern.
It is some usb driver thats are missing or wrong.
Jonas
MASTER
#include <Wire.h>
void setup() {
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
}
void loop() {
Serial.println("\n a: ");
Wire.requestFrom(3, 1);
//while (!Wire.available()){;}
uint8_t c = Wire.read();
Serial.print(c,HEX);
//}
delay(500);
}
size_t TwoWire::write(uint8_t data)
{
/* if (!_tx_active) {
return 0;
}
*/
if (_tx_write >= BUFFER_LENGTH) {
return 0;
}
_tx_data[_tx_write++] = data;
return 1;
}
[gato_ – Thu Sep 07, 2017 11:24 am] –
ok. Traced it back to function TwoWire::write(), line 175 of Wire.cpp:
size_t TwoWire::write(uint8_t data)
{
/* if (!_tx_active) {
return 0;
}
*/
if (_tx_write >= BUFFER_LENGTH) {
return 0;
}_tx_data[_tx_write++] = data;
return 1;
}
[gato_ – Thu Sep 07, 2017 9:18 am] –
The slave appers to be sending a 0 always. I checked that with a logic analyzer
![]()
That is the 2nd bug. The I2S SLAVE should send back a NACK rather than to send dummy data.
Ok. I think I will take a look on the I2c implementation
[gato_ – Fri Sep 08, 2017 1:28 pm] –
There is more. Commenting that line just fixed the 1 byte example. On trying to send several, it freezes again….
Ok. I think I will take a look on the I2c implementation
Looks like I busted the logic somewhere along the line. The onRequest() needs to also reset the tx buffer …
[GrumpyOldPizza – Fri Sep 08, 2017 2:09 pm] –[gato_ – Fri Sep 08, 2017 1:28 pm] –
There is more. Commenting that line just fixed the 1 byte example. On trying to send several, it freezes again….
Ok. I think I will take a look on the I2c implementationLooks like I busted the logic somewhere along the line. The onRequest() needs to also reset the tx buffer …
I need to rework some of the Wire.cpp code for slave mode to be compatible with Arduino Zero. Half way that is.
On a onRequest() the Arduino Zero core assumes you fill up the buffer with data, ONCE. If the master requests more data than is preset Arduino Zero sends 0xff bytes. Arduino AVR sends a proper NACK. Again, there is no refill of the TX buffer. Arduino Zero has a 64 byte sized ringbuffer class, Arduino AVR as 32 byte buffer. The corresponding _tx_active logic is active while the whole slave TX is going on. Hence it’s possible to add bytes in theory during whole transmission (plus a ton of race conditions). The Arduino AVR code assumes that you write all the data subsequent to a onRequest() callback. They do this inline without buffer, and hence block the ISR. Thus in this core, it’s not possible to write outside the onRequest() callback.
The onReceive() is somewhat more tricky it seems. Arduino AVR actually has a intermediate buffer where it reads data into, and only upon completion of this operation, data is copied into the RX buffer. That means you can read data a tad longer. Arduino Zero simply nukes the old buffer … Teensy for KINETIS follows the same logic as Arduino Zero …
For STM32L4 the attempt was made the allow segmented transmit/receive. Guess I need to change that to the Arduino Zero model, to be one-shot, and NACK on buffer underflow/overflow.
[gato_ – Tue Sep 19, 2017 9:57 am] –
Actually, the onReceive() call doesn’t seem to have any problems. And I am having some doubts about what happens with the onRequest() one. Are you using any environment to check the registers? if so, which one? what pins are employed for debugging? Thank you. Otherwise, the core is great
For debugging I am using gdb/stlink. Compile a sketch and then upload it via gdb/stlink.
I think with your discovery of _tx_active the code should perform mostly as all the other implementations do (whether that’s good or bad, I don’t know). There are only really 2 issues that needs to be addressed (again to be compatible). One is to send dummy data subsequence to a onRequest() callback if there is more data requested than buffered from the first onRequest() callback. And the other one is to send a NACK if the peer sends more data than can be buffered for a single onReceive() callback … If you have your code setup so that those conditions are not hit, you should be fine.
IMHO the real issue is the API itself (AVR and SAMD cores). If you have a onRequest() callback, you need to stuff in all the data you think might be read, up to the buffer size (which is 32 bytes for AVR). The callback will not be called again. And worse, there is no way telling how many bytes had be transferred to the peer.
I have managed to make the requestFrom example work, under certain conditions:
-The slave device must be on before the master device AND a serial terminal must be open for the slave device. Under those conditions, the master (COM8) makes the request, and the slave (COM3) answers it

-If the serial terminal of the slave is closed, then the master remains on MASTER_RECEIVE status (7) forever….

So… the usb serial interrupts affect/ modify the I2C interruptions?
The library is great, but without an I2C slave mode, it just is not usable… I am not sure on how to continue with this
EDIT: okay, so just instantiating the object in the slave (Serial.begin()) does not fix things. It turns out that I inserted some print statements in the TwoWire::EventCallback funtion. Apparently, this is a delay type of problem. The time spent printing things at some particular moments give it enough time to finish other things…
Inserted this to print statements int the EventCallback, I2C_EVENT_TRANSMIT_REQUEST case:
if (events & I2C_EVENT_TRANSMIT_REQUEST) {
_tx_write = 0;
if(_requestCallback) {
(*_requestCallback)();
}
for (int i=0;i<_tx_write;i++){Serial.print(_tx_data[i]);Serial.print(" ");}
Serial.println();
stm32l4_i2c_service(_i2c, &_tx_data[0], _tx_write);
Serial.println(_i2c->I2C->ISR&I2C_ISR_TXE);
}
It’s actually pretty trivial (apart from the bazillion I2C peripheral flags). The interrupt handler is a simple state machine:
I2C_STATE_READY
I2C_STATE_SLAVE_RECEIVE
I2C_STATE_SLAVE_TRANSMIT
I2C_STATE_MASTER_RESTART
I2C_STATE_MASTER_RECEIVE
I2C_STATE_MASTER_TRANSMIT
In I2C_STATE_READY a address match is detected. The code that handles this is in stm32l4_i2c_slave_address_match(), detecting what address, and in which direction the transfer is going. This triggers I2C_EVENT_TRANSMIT_REQUEST / I2C_EVENT_RECEIVE_REQUEST to the Wire layer to supply either data to be written, or a buffer where read data can be placed into. Anyway the state machine then switches to I2S_STATE_SLAVE_RECEIVE or I2S_STATE_TRANSMIT. For the receive part, the next ISR will either have new data (triggers a I2C_EVENT_RECEIVE_REQUEST is the buffer is full), or a I2C_EVENT_RECEIVE_DONE is a STOP or a RESTART condition is detected. I2C_STATE_MASTER_TRANSMIT is similar, except that first STOP/RESTART are detected …
The system code has a weakness in that it requires always data to be present to be send, rather than to send dummy bytes if no more TX data is supplied.
The Wire code now simply handles I2C_EVENT_RECEIVE_DONE, I2C_EVENT_RECEIVE_REQUEST and I2C_EVENT_TRANSMIT_REQUEST to supply a read buffer, or transmit data in a write buffer. The code is not 100% compatible to Arduino Zero, as there only one chunk to read/write is allowed, and overflow on the read buffer is simply ignored (data dropped), and for write 0xff bytes are sent (so no segmenting …)
[gato_ – Wed Oct 25, 2017 9:05 am] –
Well, it does show as the newest one in the boards manager. version 0.0.26
The board manager is not up to date I believe. There is some experimental code on github.
First, I had to deactivate clock stretching, as the incomplete transaction was hanging the system. the executed code is this one:
#include <Wire.h>
const int N=6;
byte buffer[N];
void setup() {
for (int i=0;i<N;i++){buffer[i]=i+1;};
Wire.begin();
Wire1.begin(3);
Wire1.onRequest(requestEvent); // register event
Serial.begin(9600);
}
void loop() {
////////request
Wire.requestFrom(3, N);
for (int i=0;i<N;i++) {
uint8_t c = Wire.read();
Serial.print(c,HEX);Serial.print(" ");
}
Serial.println();
delay(500);
}
void requestEvent() {
int s=Wire1.write(buffer,N); // respond with message of 6 bytes
}Could you share how you turned your sketch into an eclipse project with openocd debugging? I’m using this core too.
regards,
Arthur
[gato_ – Fri Dec 15, 2017 11:27 am] –
Well, learnt how to debug properly with opencd and dbg. I’m posting what I’ve found out so far.
First, I had to deactivate clock stretching, as the incomplete transaction was hanging the system. the executed code is this one:
Clock stretching is needed. Otherwise the Wire1.onRequest() callback has no time to put in data.
#include <Wire.h>
const int N=6;
byte buffer[N];
void setup() {
for (int i=0;i<N;i++){buffer[i]=i+1;};
Wire.begin();
Wire1.begin(3);
Wire1.onRequest(requestEvent); // register event
Serial.begin(9600);
}
void loop() {
////////request
Wire.requestFrom(3, N);
for (int i=0;i<N;i++) {
uint8_t c = Wire.read();
Serial.print(c,HEX);Serial.print(" ");
}
Serial.println();
delay(500);
}
void requestEvent() {
int s=Wire1.write(buffer,N); // respond with message of 6 bytes
}
Very nice work on this core, I’m impressed. I’m still working through the 15 pages of posts here and I’ve been studying the code to familiarize myself. I’ve been introduced to this core through the interesting Hackflight work here https://github.com/simondlevy/Hackfligh … master/src
I’m interested in sliding a simple time-triggered deterministic scheduler under an STM32L4 based flight controller as a learning exercise. I’m wondering if (and searching if) there is a mechanism to insert a SysTick callback or handler in this core (similar to the discussion here viewtopic.php?t=2117)? I’ve been using a Nucleo-L432KC for my test. Apologies in advance if the answer is obvious, most of my background has been AVR and I’m still climbing the ARM/CMSIS learning curve.
I’ve played around this with on the ST HAL based core using HAL_SYSTICK_Callback() (from here viewtopic.php?t=2542). but I prefer the design philosophy behind this core relative to ST HAL.
Best Regards,
George
[MGeo – Sun Jan 21, 2018 3:01 pm] –
Hello,Very nice work on this core, I’m impressed. I’m still working through the 15 pages of posts here and I’ve been studying the code to familiarize myself. I’ve been introduced to this core through the interesting Hackflight work here https://github.com/simondlevy/Hackfligh … master/src
I’m interested in sliding a simple time-triggered deterministic scheduler under an STM32L4 based flight controller as a learning exercise. I’m wondering if (and searching if) there is a mechanism to insert a SysTick callback or handler in this core (similar to the discussion here viewtopic.php?t=2117)? I’ve been using a Nucleo-L432KC for my test. Apologies in advance if the answer is obvious, most of my background has been AVR and I’m still climbing the ARM/CMSIS learning curve.
I’ve played around this with on the ST HAL based core using HAL_SYSTICK_Callback() (from here viewtopic.php?t=2542). but I prefer the design philosophy behind this core relative to ST HAL.
Best Regards,
George
Yes, there is … But it’s not part of Arduino class (yet):
typedef struct _armv7m_timer_t armv7m_timer_t;
typedef void (*armv7m_timer_callback_t)(armv7m_timer_t *timer);
struct _armv7m_timer_t {
armv7m_timer_t *next;
armv7m_timer_t *previous;
volatile armv7m_timer_callback_t callback;
uint32_t remaining;
};
#define ARMV7M_TIMER_INIT(_callback,_timeout) { NULL, NULL, (_callback), (_timeout) }
extern void armv7m_timer_create(armv7m_timer_t *timer, armv7m_timer_callback_t callback);
extern bool armv7m_timer_start(armv7m_timer_t *timer, uint32_t timeout);
extern bool armv7m_timer_stop(armv7m_timer_t *timer);
I see there is armv7m_systick_notify() in armv7m.c, would I be able to register my own callback via this function, with context = NULL? Or is it best to set up a Timer object for that?
void armv7m_systick_notify(armv7m_systick_callback_t callback, void *context)
{
armv7m_systick_control.callback = NULL;
armv7m_systick_control.context = context;
armv7m_systick_control.callback = callback;
}
[MGeo – Tue Jan 23, 2018 11:29 am] –
Ok thanks trying to follow you.I see there is armv7m_systick_notify() in armv7m.c, would I be able to register my own callback via this function, with context = NULL? Or is it best to set up a Timer object for that?
void armv7m_systick_notify(armv7m_systick_callback_t callback, void *context)
{
armv7m_systick_control.callback = NULL;
armv7m_systick_control.context = context;
armv7m_systick_control.callback = callback;
}
I’m more or less following the design philosophy of this https://www.safetty.net/download/pont_e … xtract.pdf
For this high integrity scheduler co-operative scheduler I would want to hook SysTick, and be aware of any higher priority interrupts that may interfere with task timing. So understanding the core workings is part of my learning exercise here. The followings appear to work as expected, very cool:
/*
GrumpyOldPizza L4 Core on NUCLEO-L432KC board.
Test to hook SysTick, incremeent a counter in SysTick callback,
toogle LED on for one second, then off for one second, repeatedly.
*/
// Pin 13 has an LED connected on most Arduino boards
int led = 13;
volatile bool oneSecFlag = false;
volatile int16_t oneSecCount = 0;
// the setup routine runs once when you press reset:
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Setting up...");
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
//armv7m_systick_notify(L4_SYSTICK_Callback, NULL);
armv7m_systick_notify( (armv7m_systick_callback_t)L4_SYSTICK_Callback, NULL);
}
// the loop routine runs over and over again forever:
void loop() {
if (oneSecFlag == true) {
Serial.println("One Second Event has occured, clearing oneSecFlag");
oneSecFlag = false;
digitalWrite(led, !digitalRead(led));
}
Serial.print("oneSecCount = "); Serial.println(oneSecCount);
delay(100);
}
armv7m_systick_callback_t L4_SYSTICK_Callback(void) {
oneSecCount++;
if (oneSecCount >= 1000) {
oneSecFlag = true;
oneSecCount = 0;
}
}
[MGeo – Tue Jan 30, 2018 11:00 am] –
Ok, I’ll beg for forgiveness on not following directions….
I’m more or less following the design philosophy of this https://www.safetty.net/download/pont_e … xtract.pdf
For this high integrity scheduler co-operative scheduler I would want to hook SysTick, and be aware of any higher priority interrupts that may interfere with task timing. So understanding the core workings is part of my learning exercise here. The followings appear to work as expected, very cool:
/*
GrumpyOldPizza L4 Core on NUCLEO-L432KC board.
Test to hook SysTick, incremeent a counter in SysTick callback,
toogle LED on for one second, then off for one second, repeatedly.
*/// Pin 13 has an LED connected on most Arduino boards
int led = 13;volatile bool oneSecFlag = false;
volatile int16_t oneSecCount = 0;// the setup routine runs once when you press reset:
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Setting up...");
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
//armv7m_systick_notify(L4_SYSTICK_Callback, NULL);
armv7m_systick_notify( (armv7m_systick_callback_t)L4_SYSTICK_Callback, NULL);
}// the loop routine runs over and over again forever:
void loop() {if (oneSecFlag == true) {
Serial.println("One Second Event has occured, clearing oneSecFlag");
oneSecFlag = false;
digitalWrite(led, !digitalRead(led));
}
Serial.print("oneSecCount = "); Serial.println(oneSecCount);
delay(100);
}armv7m_systick_callback_t L4_SYSTICK_Callback(void) {
oneSecCount++;
if (oneSecCount >= 1000) {
oneSecFlag = true;
oneSecCount = 0;
}
}
Having updated the IDE accordingly to the instrucktion of
https://github.com/GrumpyOldPizza/arduino-STM32L4
And running the example
https://github.com/GrumpyOldPizza/ardui … /SimpleRTC
I’m wondering if there is a way to enable compilation of the RTC lib with the boards of stm32duino packages in order to be able to combine examples from the two setups – or am I doing something wrong – or is there already a RTC lib from stm32duino (especially F4 and L4)..?
Best regards,
Frank


