Monday, July 17, 2017

Using a Raspberry Pi3 as an OpenOCD server

Cheap and plentiful, a Raspberry Pi3 makes an excellent OpenOCD server. You can place it near your target and just attach to it from where you do your builds. On my Pi3 server I have openocd-0.9.0 and openocd-0.10.0, the win with a Pi3 is it has WLAN, so permit it to sign on to your network, preferably with a known static IP, and then you can ssh over to it and start openocd:

root@pi3:~/openocd-0.10.0/tcl# ../src/openocd --file board/st_nucleo_l476rg.cfg
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : The selected transport took over low-level target control. The results mi
ght differ compared to plain JTAG/SWD
adapter speed: 480 kHz
adapter_nsrst_delay: 100
none separate
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
Info : clock speed 480 kHz
Info : STLINK v2 JTAG v25 API v2 SWIM v14 VID 0x0483 PID 0x374B
Info : using stlink api v2
Info : Target voltage: 3.262028
Info : stm32l4x.cpu: hardware has 6 breakpoints, 4 watchpoints


Now you have a connection to your board.

On another machine where you do your dev, (in my case a box in an upstairs server room) you just allow GDB to connect to it via the static IP:

admin@ubuntu_1604:/.share/CACHEDEV1_DATA/Ada/STM32/L432/dac_sw$ arm-eabi-gdb obj
/Debug/dac_sw
GNU gdb (GDB) 7.10 for GNAT GPL 2016 [rev=gdb-7.10-ref-161-g9bf8eca]
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
See your support agreement for details of warranty and support.
If you do not have a current support agreement, then there is absolutely
no warranty for this version of GDB.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-eabi".
Type "show configuration" for configuration details.For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from obj/Debug/dac_sw...done.
(gdb) target extended-remote 10.0.1.241:3333
Remote debugging using 10.0.1.241:3333
0x00000000 in ?? ()
(gdb) monitor reset halt
Unable to match requested speed 500 kHz, using 480 kHz
Unable to match requested speed 500 kHz, using 480 kHz
adapter speed: 480 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08004420 msp: 0x200006d0
(gdb) load
Loading section .text, size 0xc2e4 lma 0x8000000
Loading section .ARM.extab, size 0x7c4 lma 0x800c2e4
Loading section .ARM.exidx, size 0xaa0 lma 0x800caa8
Loading section .rodata, size 0x1d50 lma 0x800d548
Loading section .data, size 0x2c4 lma 0x800f298
Start address 0x8007348, load size 62812
Transfer rate: 22 KB/sec, 7851 bytes/write.
(gdb) monitor reset init
Unable to match requested speed 500 kHz, using 480 kHz
Unable to match requested speed 500 kHz, using 480 kHz
adapter speed: 480 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08007348 msp: 0x2000cb20
adapter speed: 4000 kHz
(gdb) b main
Breakpoint 1 at 0x80007b6: file b__dac_sw.adb, line 176.
(gdb) b __gnat_last_chance_handler
Breakpoint 2 at 0x800a0be
(gdb) c
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.
Breakpoint 1, main () at b__dac_sw.adb:176
176           Ensure_Reference : aliased System.Address := Ada_Main_Program_Name
'Address;
(gdb)


The real win is you have 4 USB ports for connections to targets. Also the Adafruit SiLabs USB<->RS232 dongle works well so you can get UART data from an embedded target. With a Pi2 you lose one USB port for the WLAN dongle.


Here seen connected to the STM32L432 nucleo and is the target from the session show above. Also in the light blue housing we see the Adafruit usb to ttl serial cable.

https://www.adafruit.com/product/954

Friday, July 14, 2017


Building a motion sensing camera with a Raspberry Pi

A Raspberry Pi and a pinoir camera make for a good motion capture camera. There is always an impetus to hack, the impetus in this case came from theft at my company. At night, someone had been walking off with hardware from cubicles. One was just down my aisle and was perhaps too close to home.  Not wanting any of my stuff wandering off, I wanted a camera that would record motion and save video only around the event. I did not want to process 8 hours of raw, mainly motionless video each day when I came in. Currently as it works, each file per night is about 80MB. These files are saved over the LAN on a file server, in this way not polluting the SD card on the Pi. The files can be viewed by VLC and are H.264.

For the motion sensor, an Adafruit PiR sensor is used:

https://www.adafruit.com/product/189

This sensor needs some connectors added, a small crimp connector is added to the bare wires and hot air used to shrink a sleeve around the bare connector. For quick and dirty hacking, my goto language these days is Ruby, this project was no exception. A gem called PiPiper (Silicon Valley fans?) is used to convert GPIO levels to events that Ruby can act on. An event called out by the GPIO going high is generated by the sensor when there is motion, this in turn unblocks a forked raspivid process (raspivid being the canned camera app the RaspberryPi foundation ships). So, via 2 signals SIGSTOP and SIGCONT we can command raspivid to stop and go. raspivid has some buffering already in place so when you say SIGCONT it has the last N seconds of vid ready to go, then the camera is allowed to proceed for some grace period after the event. Finally, via a timer, the SIGSTOP is sent. In this way, smaller video files are generated.

I am using GPIO 18 for the event pin.


The setup looks as above, a PiR connected to a Pi3. On the wall is a 12v IR ring for night illumination, it glows a dull crimson as its photodetector senses darkening ambient conditions.

The code is here:

https://github.com/morbos/ruby/tree/master/motion

Some issues:

1) No RTC on the Pi. I have a cheap $8 Banggood kit clock thats in the field of view. That is my source of time. The console output on the Pi helps also, as long as you have the correct time set on the Pi.
2) I recommend a Pi3 as it can do more than just this and is useful to have around. I am cabled up as I found that every 30secs or so the WLAN emits a wpa supplicant pkt that couples with the sensor and generates false events.
% ifdown wlan0

3) Audio would be a plus.


ARM Cortex SVD files

A lot of goodness can be represented by an SVD file.

The full name is CMSIS-SVD and was designed by Keil who was acquired by ARM. All reasonable ARM Cortex vendors these days who want users to program their targets have SVD files. The scope of the SVD file covers all the peripherals in the designs down to the numerical addresses.

Here is an extract from the STM32L432's SVD file. We see the DAC is at a baseAddress of 0x40007400 and the first reg in the DAC is the CR or control reg at offset 0, further, we see the individual fields of the CR with EN1 at bit position 0.

  <peripherals>
    <peripheral>
      <name>DAC1</name>
      <description>Digital-to-analog converter</description>
      <groupName>DAC</groupName>
      <baseAddress>0x40007400</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x400</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>CR</name>
          <displayName>CR</displayName>
          <description>control register</description>
          <addressOffset>0x0</addressOffset>
          <size>0x20</size>
          <access>read-write</access>
          <resetValue>0x00000000</resetValue>
          <fields>
            <field>
              <name>EN1</name>
              <description>DAC channel1 enable</description>
              <bitOffset>0</bitOffset>
              <bitWidth>1</bitWidth>
            </field>
      etc

This is great info! Can we use it to make our life as programmers smoother? As an embedded programmer I use ST cores and GDB to debug them. I have put together a couple of Ruby 2.x scripts that suck in the SVD file and emit a GDB script. The first Ruby script generates this:

set pagination off
set logging overwrite on
set logging file DAC1.log
set logging on
set logging redirect on
x/256x 0x40007400
set logging redirect off
set logging off
set logging file DMA1.log
set logging on
set logging redirect on
x/256x 0x40020000
set logging redirect off
set logging off

etc

Now in GDB you just say:

source filename 

Where filename is the output of the first Ruby script. So that's great, now we have a binary file of data for each peripheral in the SVD file as realized from our target processor when we stopped it.

It would be great if we could interpret the binary data in those dumps in a form that's human readable and can be diff'ed from one capture to another. This technique works well for binary blobs also if you can break in. You just run the next script and look at what changed in the controller. So lets look at a use case with the ADC (same part STM32L432KC):


0x50040000:     0x0000007f      0x00000000      0x10000005      0xfffe2000
0x50040010:     0x00000000      0x00028000      0x00000000      0x00000000
0x50040020:     0x0fff0000      0x00ff0000      0x00ff0000      0x00000000
0x50040030:     0x00000140      0x00000000      0x00000000      0x00000000
0x50040040:     0x00000231      0x00000000      0x00000000      0x00000000
0x50040050:     0x00000000      0x00000000      0x00000000      0x00000000
0x50040060:     0x00000000      0x00000000      0x00000000      0x00000000
0x50040070:     0x00000000      0x00000000      0x00000000      0x00000000
0x50040080:     0x00000264      0x00000000      0x00000000      0x00000000
0x50040090:     0x00000000      0x00000000      0x00000000      0x00000000
0x500400a0:     0x00000000      0x00000000      0x00000000      0x00000000
0x500400b0:     0x00000000      0x0000003a      0x00000000


After the second script:

ADC.ISR.JQOVF: 0
ADC.ISR.AWD3: 0
ADC.ISR.AWD2: 0
ADC.ISR.AWD1: 0
ADC.ISR.JEOS: 1
ADC.ISR.JEOC: 1
ADC.ISR.OVR: 1
ADC.ISR.EOS: 1
ADC.ISR.EOC: 1
ADC.ISR.EOSMP: 1
ADC.ISR.ADRDY: 1
ADC.IER.JQOVFIE: 0
ADC.IER.AWD3IE: 0
ADC.IER.AWD2IE: 0
ADC.IER.AWD1IE: 0
ADC.IER.JEOSIE: 0
ADC.IER.JEOCIE: 0
ADC.IER.OVRIE: 0
ADC.IER.EOSIE: 0
ADC.IER.EOCIE: 0
ADC.IER.EOSMPIE: 0
ADC.IER.ADRDYIE: 0
ADC.CR.ADCAL: 0
ADC.CR.ADCALDIF: 0
ADC.CR.DEEPPWD: 0
ADC.CR.ADVREGEN: 1
ADC.CR.JADSTP: 0
ADC.CR.ADSTP: 0
ADC.CR.JADSTART: 0
ADC.CR.ADSTART: 1
ADC.CR.ADDIS: 0
ADC.CR.ADEN: 1
ADC.CFGR.AWDCH1CH[4:0]: 0x1f
ADC.CFGR.JAUTO: 1
ADC.CFGR.JAWD1EN: 1
ADC.CFGR.AWD1EN: 1
ADC.CFGR.AWD1SGL: 1
ADC.CFGR.JQM: 1
ADC.CFGR.JDISCEN: 1
ADC.CFGR.DISCNUM[2:0]: 7
ADC.CFGR.DISCEN: 0
ADC.CFGR.AUTOFF: 0
ADC.CFGR.AUTDLY: 0
ADC.CFGR.CONT: 1
ADC.CFGR.OVRMOD: 0
ADC.CFGR.EXTEN[1:0]: 0
ADC.CFGR.EXTSEL[3:0]: 0
ADC.CFGR.ALIGN: 0
ADC.CFGR.RES[1:0]: 0
ADC.CFGR.DMACFG: 0
ADC.CFGR.DMAEN: 0
ADC.CFGR2.ROVSM: 0
ADC.CFGR2.TOVS: 0
ADC.CFGR2.OVSS[3:0]: 0
ADC.CFGR2.OVSR[2:0]: 0
ADC.CFGR2.JOVSE: 0
ADC.CFGR2.ROVSE: 0
ADC.SMPR1.SMP9[2:0]: 0
ADC.SMPR1.SMP8[2:0]: 0
ADC.SMPR1.SMP7[2:0]: 0
ADC.SMPR1.SMP6[2:0]: 0
ADC.SMPR1.SMP5[2:0]: 5
ADC.SMPR1.SMP4[2:0]: 0
ADC.SMPR1.SMP3[2:0]: 0
ADC.SMPR1.SMP2[2:0]: 0
ADC.SMPR1.SMP1[2:0]: 0
ADC.SMPR1.SMP0[2:0]: 0
ADC.SMPR2.SMP18[2:0]: 0
ADC.SMPR2.SMP17[2:0]: 0
ADC.SMPR2.SMP16[2:0]: 0
ADC.SMPR2.SMP15[2:0]: 0
ADC.SMPR2.SMP14[2:0]: 0
ADC.SMPR2.SMP13[2:0]: 0
ADC.SMPR2.SMP12[2:0]: 0
ADC.SMPR2.SMP11[2:0]: 0
ADC.SMPR2.SMP10[2:0]: 0
ADC.TR1.HT1[11:0]: 0xfff
ADC.TR1.LT1[11:0]: 0
ADC.TR2.HT2[7:0]: 0xff
ADC.TR2.LT2[7:0]: 0
ADC.TR3.HT3[7:0]: 0xff
ADC.TR3.LT3[7:0]: 0
ADC.SQR1.SQ4[4:0]: 0
ADC.SQR1.SQ3[4:0]: 0
ADC.SQR1.SQ2[4:0]: 0
ADC.SQR1.SQ1[4:0]: 5
ADC.SQR1.L3[3:0]: 0
ADC.SQR2.SQ9[4:0]: 0
ADC.SQR2.SQ8[4:0]: 0
ADC.SQR2.SQ7[4:0]: 0
ADC.SQR2.SQ6[4:0]: 0
ADC.SQR2.SQ5[4:0]: 0
ADC.SQR3.SQ14[4:0]: 0
ADC.SQR3.SQ13[4:0]: 0
ADC.SQR3.SQ12[4:0]: 0
ADC.SQR3.SQ11[4:0]: 0
ADC.SQR3.SQ10[4:0]: 0
ADC.SQR4.SQ16[4:0]: 0
ADC.SQR4.SQ15[4:0]: 0
ADC.DR.regularDATA[15:0]: 0x231
ADC.JSQR.JSQ4[4:0]: 0
ADC.JSQR.JSQ3[4:0]: 0
ADC.JSQR.JSQ2[4:0]: 0
ADC.JSQR.JSQ1[4:0]: 0
ADC.JSQR.JEXTEN[1:0]: 0
ADC.JSQR.JEXTSEL[3:0]: 0
ADC.JSQR.JL[1:0]: 0
ADC.OFR1.OFFSET1_EN: 0
ADC.OFR1.OFFSET1_CH[4:0]: 0
ADC.OFR1.OFFSET1[11:0]: 0
ADC.OFR2.OFFSET2_EN: 0
ADC.OFR2.OFFSET2_CH[4:0]: 0
ADC.OFR2.OFFSET2[11:0]: 0
ADC.OFR3.OFFSET3_EN: 0
ADC.OFR3.OFFSET3_CH[4:0]: 0
ADC.OFR3.OFFSET3[11:0]: 0
ADC.OFR4.OFFSET4_EN: 0
ADC.OFR4.OFFSET4_CH[4:0]: 0
ADC.OFR4.OFFSET4[11:0]: 0
ADC.JDR1.JDATA1[15:0]: 0x264
ADC.JDR2.JDATA2[15:0]: 0
ADC.JDR3.JDATA3[15:0]: 0
ADC.JDR4.JDATA4[15:0]: 0
ADC.AWD2CR.AWD2CH[17:0]: 0
ADC.AWD3CR.AWD3CH[17:0]: 0
ADC.DIFSEL.DIFSEL_1_15[14:0]: 0
ADC.DIFSEL.DIFSEL_16_18[2:0]: 0
ADC.CALFACT.CALFACT_D[6:0]: 0
ADC.CALFACT.CALFACT_S[6:0]: 0x3a

So now we can study the regs with symbolic output when we consult the datasheets for these types of controllers.

The Ruby scripts are here:

https://github.com/morbos/ruby


Welcome! to hrrzi.com

The name comes from the half-word instructions on the 36bit KL-10 processor.

http://pdp10.nocrew.org/docs/instruction-set/Half-Word.html

So for this blog the hrrzi instruction means halfword from the right to the right, zeroes on the left hand size, and an 18bit immediate in the right half.



[Toad-1] LS:<~>@ type HW2.MAC
title hw2
search monsym
start: reset
hrrzi 1,message
psout
haltf
message: asciz /
HRRZI - Hedley Rainnie's blog
/
end start

[Toad-1] LS:<~>@ exec HW2
LINK: Loading
[LNKXCT HW2 execution]

HRRZI - Hedley Rainnie's blog