Category Archives: stm32

Revised MRF24J40 driver code for STM32 and AVR

I meant to post this a while ago, but oh well :) A long time ago I made a basic driver for AVR, then I hacked it up a bit to make it run on the STM32L discovery board. None of the code was common, and the STM32 code was some of my earliest steps in that world. Last summer I started trying to put this all together, but I got busy with other things, and more particularly, I ditched the ST Standard Peripheral Lib and started actively working on libopencm3. Anyway, I eventually got back into project mode, and decided it was time to tidy this all up.

So, here it is. The 3rd edition of my MRF24J40 code. This one should be somewhat more portable to other platforms, as it uses function pointers to set up all the spi and interrupts. (As if anyone else is using this stuff anyway!)

https://github.com/karlp/simrf

There’s still plenty of tidying up that could be done, there always is, but it’s more going to be a base for further work on Contiki, so it’s probably about as good as it’s getting for now.

Porting Contiki to the STM32L

WARNING – rambling diatribe that might help me….

This is mostly a notepad of what I did, why I think I did it, and what I couldn’t find documented anywhere obvious at the time of writing

Motivation: I am interested in low power wireless sensor nodes. Most of the commonly used MCU operating systems I had looked at treated power usage as a second class citizen at best (if at all) Contiki builds all that in, it’s a primary concern. I abhor the idea of custom wireless protocols (even though I hacked one up for the current nodes in my house) Contiki builds in IPv6 (amongst other protocols) and knows explicitly about 802.15.4 (what I like to use) IP all the way sounds like a pretty smart bet.

So, I want to use contiki on my devices.

Right, big blob of unknown new code. What do I need, where does it need to go…. There’s a rather ugly blob of code in the repository that supports the STM32W series (a rather awkward part to use. No reference manual, binary blobs of radio drivers, the complete inability to order them to Iceland thanks to arbitrary export encryptions, etc) so maybe it would be easy. The code makes no real sense, and seems to be completely abandoned. There’s meant to be ARM support though, so shouldn’t be too hard.

Hrmm. code is split between “cpu” and “platform” Hard to know what should be where.
Oh! Someone just added support for the stm32F1, a chip I know well, no radio driver yet, but that’s ok, I know the MRF24J40 radio well, and would be using that anyway.

Oh, that code got reverted due to (to me) a fairly arbitrary lpgl vs bsd arguments (despite the stm32w code having a binary blob radio driver, let’s not start in there)

Ok, so, nothing says I can’t have my own fork, at least while licensing is worked out. https://github.com/contiki-os/contiki/wiki/Out-of-Tree-Development is the best reference I’ve found for getting started so far.

Now, I’ve got the hello world “app” copied into my tree as “foo” and I can do “make” and then ./foo.native and it works.

 karlp@tera:~/src/kcontiki (master *)$ ./foo.native 
Contiki 2.6 started
Rime started with address 2.1
MAC nullmac RDC nullrdc NETWORK Rime
Hello foo world
^C

Excellent, now what? Now I start to leave the comfort of the directions. I decide to copy the reverted stm32f107_basic platform into my tree, still following the Out of Tree Development guide

I’ve added libopencm3 as a git submodule too now. I can do “make TARGET=stm32ldiscovery” and it sort of works, in that it finds platforms/stm32ldiscovery/Makefile.stm32ldiscovery. Now I just need to know what _else_ is needed to go into that makefile. What’s in it now? MCK=72000000, do I really need that? I’d like to not have to care in a makefile. Hrmm. I guess what is really next is sorting out what is part of cpu/arm/xxx and what goes into platform/stm32ldiscovery.

CONTIKI_TARGET_MAIN. What’s that for? why do I need that? grepping the source shows totally inconsistent usages of it. Let’s ignore that for now.

Ok, the libopencm3 based stm32f107basic tree has a uart driver and some newlib stubs. Let’s keep as much of that as possible, and just hack the uart driver to be L1 based rather than F1 based. (This is actually just a difference in gpio AF function settings, the uart code is all identical)

That seems to get a little further, but now we need to get the cpu/arm/stm32f1x_cl code to work out somehow. let’s see how much of that is really “platform” Ok clock.c is opencm3 specific, but not f1x specific. OH! Here’s the MCK setting being used. ok, we’ll set that. rtimer* and mtarch* are all stubs, so that’s ok for now too.

So, a bit more hacking on the cpu/arm/stm32f1x_cl makefile to make it a little more of a “stm32 libopencm3” makefile, and we have a build!

But… does it work? No. setvbuf goes straight into the blocking handler, and puts does too. I guess something didn’t get linked or built properly. But we’re getting somewhere. I’ll look at the backtrace a bit later on, but it’s late.

Code so far in

arm-none-eabi-gdb with python support on linux (Fedora 17)

I’ve been using the GCC ARM Embedded toolchain for STM32 development on linux for a while now. It’s maintained by ARM, it’s available for linux, windows and osx, and it’s just a zip of binaries. Untar, add to your path, and you’re golden. With the new 4.7 release (2012q4) it includes some decent code size improvements, and is generally just a one stop shop for getting a toolchain.

However, the linux builds don’t have python support in GDB. This isn’t necessarily a bad thing, but people are starting to put together some nice tools that plugin to GDB that rely on python support. There’s some experimental SWV/SWO support, there’s some neat support for printf without printf and, what I’m trying to do, dump a lot of data buffers straight out of ram on the target device for analysis in python.

So, I tried building it myself. I first tried just downloading recent gdb sources and adding python support, after setting the target to arm-none-eabi. but….. that didn’t play well with openocd, so I went back to trying to build the G-A-E provided sources instead.

Here’s what I needed on Fedora 17 x64

  • libmpc-devel
  • expat-devel
  • ncurses-devel
  • python-devel
  • bison

This then replaces step 5 from the provided instructions…

$ cd [extracteddir]/src
[dir]/src$ tar -xf gdb.tar.gz
[dir]/src$ cd gdb
./configure --with-expat --with-python --target=arm-none-eabi
make -j5

That got me a working gdb with python support…

Code Size changes with “int” on 8bit and 32bit platforms

I was looking for a few bytes extra flash today, and realized that some old AVR code I had, which used uint8_t extensively for loop counters and indexes (dealing with small arrays) might not be all that efficient on the STM32 Cortex-M3.

So, I went over the code and replaced all places where the size of the counter wasn’t really actually important, and made some comparisons. I was compiling the exact same c file in both cases, with only a type def changing between runs.

Compiler versions and flags

platform gcc version cflags
AVR avr-gcc (GCC) 4.3.5 -DNDEBUG -Wall -Os -g -ffunction-sections -fdata-sections -Wstrict-prototypes -mmcu=atmega168 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
STM32 arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.6.2 20120316 (release) [ARM/embedded-4_6-branch revision 185452] -DNDEBUG -Wall -Os -g -ffunction-sections -fdata-sections -Wstrict-prototypes -fno-common -mcpu=cortex-m3 -mthumb

And… here’s the results

counter type avr-size arm-none-eabi-size
unsigned int 1318 844
uint8_t (original) 1160 856
uint_least8_t 1160 856
uint_fast8_t 1160 844
int 1330 820
int8_t 1212 872
int_least8_t 1212 872
int_fast8_t 1212 820

I would personally say that it looks like ARM still has some work to go on optimizations. If _least8 and _fast8 take up more space than int it’s not really as polished as the avr-gcc code yet. For me personally, as this code no longer has to run on both AVR and STM32, I’ll just use int.

So, after extending this a bit, my original conclusion about the fast_ types not being fully optimized with arm-gcc were wrong. It’s more that, on AVR, your “don’t care” counters should be unsigned for smaller size, while on STM32, they should be signed (Though I still think it’s dodgy that int_least8_t resulted in bigger code than int_fast8_t) Also, even if signed is better in the best case, the wrong signed is also the worst case. Awesome.

STM32 Device Electronic Signature – Unique Device ID Register

STM32 parts, in all families, have a “Device Electronic Signature” block, which contains a Unique Device ID register of 96 bits. It’s burnt in to the part during manufacture, and is guaranteed to be unique for any device in any context Now, 96 bits is fairly large, and in one application of mine, I need an 8 bit number that reliably varies between devices, and also a 48bit serial number. (Like a MAC address, or EUI48) The canonical way of doing this is to hash the large value to get a small value. I was hoping to use 48 bits of the unique id as “unique enough”

ST doesn’t provide much/any information about what goes into this 96 bit number, but there’s internet rumours that it includes things like wafer x,y position, manufacturing datecodes and so on. If I want something that reliably varies, I need to know a little bit more. I don’t have anything really conclusive, but it looks like I really will have to hash the unique id. Here’s the unique id bits from three STM32F100C8 parts purchased from mouser in the same lot. (Can’t find the order date right now)

device uniqueid[95:64] uniqueid[63:32] uniqueid[31:0]
STM32F100C8-A 0x43023307 0x36314732 0x06E30030
STM32F100C8-B 0x43022507 0x36314732 0x06CF0030
STM32F100C8-C 0x43022407 0x36314732 0x06D10030
STM32F100RB (STM32VL Discovery board) 0x43172128 0x30345532 0x06B30036

On the STM32F0 datasheet, the bits are actually described, and there’s no real reason to assume that it ever changed. They list bits 95:64 as LOT_NUM[55:24], bits 63:40 as LOT_NUM[23:0], bits 39:32 as WAF_NUM[7:0] and bits 31:0 as X and Y coordinates on the wafer expressed in BCD format. That would imply that my three parts in the same box came from the same wafter, but different lot numbers. So, well, maybe it was a different scheme for the F1 :)

Looks like I’ll be hashing anyway then :)

The strange prices of chips at distributors (STM32F100 prices)

A while ago I bought some STM32F100C8 chips (64k flash, 8k sram) because they were cheaper than the F100C6 chips, 32k flash, 4 k sram. At least at the time. I was recently looking at them again, and decided to price chart the whole family of STM32F100Cxxxx, across Digiey, Mouser and Farnell (/Newark/element14 etc)

STM32F100C is the 48pin LQFP package. Results were interesting to say the least. Prices are for 100 units, so not huge scale, but more than just a couple of prototypes. Prices are in USD, and were advertised when I wrote this post.

Points of note

  • Newark/farnell cheaper almost across the board. That’s unusual for us, but we may have to look at them a bit more often now :)
  • DigiKey is the only one where the price actually goes up as you increase the specs. Mouser has the C6 cheaper than the C4, and Newark/Farnell has the CB cheaper than the C8
Part flash ram DigiKey Mouser Newark/Farnell
STM32F100C4 16KB 4KB 1.98 2.11 1.64
STM32F100C6 32KB 4KB 2.091 1.99 1.91
STM32F100C8 64KB 8KB 2.8085 2.93 2.89
STM32F100CB 128KB 8KB 3.239 3.09 2.87

Interrupt Service Routines double firing on STM32

This is just a quick note to self. Remember, never try and clear the flag that caused the interrupt as the last instruction in the ISR itself. It causes the ISR to reenter immediately. Your ISR/NVIC/EXTI interrupt will retrigger, trigger twice, whatever keyword you were searching for.

void exti9_5_isr(void)
{
    state.my_counter++;
    exti_reset_request(EXTI5);  // Will cause a double interrupt
}

It’s just a matter of doing it first.

void exti9_5_isr(void)
{
    exti_reset_request(EXTI5);  // This will work
    state.my_counter++;
}

Code examples are based on libopencm3, but the same concept applies when using StdPeriphLib

Using netbeans for STM32 development with stlink (texane)

So, You got a STM32 Discovery board hey? Good for you! They’re cheap, and highly functional, but this ain’t your grandmother’s Arduino.

Here’s a rough and ready howto for developing in netbeans, and getting source level debugging for that code.

Required pieces

GNU arm toolchain installed and working.

I use summon-arm-toolchain for this. To test that it’s working, you can try any of the following:

You want to make sure that you can successfully compile via make from the command line first. If you can’t compile with the raw tools, netbeans isn’t going to magically fix that for you.

texane/stlink

A confusing name, but so be it. stlink (the software tool) provides tools for flashing STM32 chips via ST/Link v1 and v2 hardware. It also provides a gdbserver for debugging those chips. Get it from github (Sorry, there’s no tagged releases or anything yet, though there really should be)

Netbeans

Duh, this post is covering that. You need the c/c++ plugin and the gdbserver plugin. Download it here. For reference, I’m using 7.1 at the moment.

Setting up the toolchain in netbeans

  1. Click Tools->Options->C/C++
  2. Click on “Add” and set up a new toolchain for arm development. See the screenshot below
    Netbeans add tools dialog for gnu-arm

    Netbeans add tools dialog for gnu-arm

  3. Import your project as a makefile based project from existing sources. You can get netbeans to actually do all the compiling and things for you, but I find it hard to share the project that way. Not everyone uses netbeans, but makefiles are pretty portable.
  4. Build your project
  5. Flash your binary to the target. You can actually do this anyway you want, but we’ll use stlink’s st-flash tool.
    $ arm-none-eabi-objcopy -O binary your_project.elf your_project.bin
    $ /path/to/stlink/flash/st-flash write your_project.bin 0x08000000
    

    Here’s a screenshot from my makefile. (You can set up run modes in netbeans to do this too, but that’s not the focus here)

    console log for make and upload via stlink

    make and upload via stlink

  6. Start stlink’s gdbserver.
    karlp@tera:~/src/stlink$ ./gdbserver/st-util 
    2012-05-03T20:44:56 INFO src/stlink-common.c: Loading device parameters....
    2012-05-03T20:44:56 INFO src/stlink-common.c: Device connected is: L1 Med-density device, id 0x10186416
    2012-05-03T20:44:56 INFO src/stlink-common.c: SRAM size: 0x4000 bytes (16 KiB), Flash: 0x20000 bytes (128 KiB) in pages of 256 bytes
    Chip ID is 00000416, Core ID is  2ba01477.
    init watchpoints
    Listening at *:4242...
    
  7. Whew, ok, just about there. Now in netbeans, choose “Debug->Attach debugger”.
  8. Choose “gdbserver” and make sure you put in the right host and port, (normally localhost, and 4242) and make sure it’s set to debug your project.
    screenshot for netbeans gdbserver attach dialog

    gdbserver-attach

  9. MAKE SURE you have set at least one breakpoint first. Something in netbeans doesn’t like adding breakpoints while it’s running, and it doesn’t like pressing the pause button. (but see the footnotes)
  10. Profit…
    screenshot showing netbeans Source debugging STM32 via stlink gdbserver

    Source debugging STM32 via stlink gdbserver

  11. That’s it. If any of the steps are glossed over too much, mail me and I’ll try and update to clarify.

    Sidenote: If you didn’t set any breakpoints in netbeans first, or you pressed pause, or you double clicked in the gutter to add some breakpoints, and nothing happened, you’ve hit whatever weirdness is in the gdbserver plugin. This problem is reported with other stm32 gdbservers, so it doesn’t appear to be a problem with stlink, but with netbeans. You can wake up netbeans again with kill -INT $(pidof arm-none-eabi-gdb)
    Thanks to gsmcmullin on ##stm32 on irc.freenode.net for that gem.

    Update for netbeans 7.2: Apparently you now have to put “target localhost:4242” into the gdbserver box, not just “localhost:4242”.

MRF24J40 driver for STM32

A while ago I put together a C driver for the MRF24J40 802.15.4 modules from microchip. I had been using them as a cheap alternative to xbees in some AVR projects. As I’ve been moving on to STM32 parts for hobby projects, (more power, cheaper) I started off porting my driver code from AVR over to cortex m3.

This has been quite an experience. The arm toolchain experience, and particularly the libc support and general documentation is completely different to, say, avr-libc (AVR-libc is a great project, reallly solid)

However, with lots of learning, and lots of mistakes, I’ve got it all working. It’s a first cut, but the basic features are there. There’s no magic for DMA, and you have to do a lot of the pin setup yourself, but this is Cortex M3, there’s so many pins you could be using for this! I’ve tried to reduce the required function calls as much as possible, but there’s still room for improvement.

    // Required by the user code
    extern void mrf_select(void);  // Chip select, if necessary
    extern void mrf_deselect(void);  // chip deselect, if necessary
    extern uint8_t spi_tx(uint8_t cData);
    extern void _delay_ms(int);  // only used at init time.

This still needs to move to a clear sub project, currently it’s a separate code base to the AVR code.

Get the code now!

More to come, as it gets tidied up and put into use!

Taking quiet output to the next level

I don’t know who thought this was a good idea, but this is the output of a successful build for one of the examples in the libopencm3 project


karlp@tera:~/opencm3_f4$ make clean
karlp@tera:~/opencm3_f4$ make
karlp@tera:~/opencm3_f4$

Really? Realllly? Ok, concise output is good, but this is no output at all!

Probably the same people who think making a stdlib implementation that is GPL….