Skip to main content
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


Comments

Popular posts from this blog

The Air32F103

 Bluepills Its no surprise that Bluepills, such as they were, a smoking sub $2 deal would dry up eventually, taken over by clones, some subtle, some overt. With supply issues still plaguing ST parts for hobbyists, what about these cheap Chinese clone parts? Lets dive into the Air32F103. Air32F103 I bought 5 of these $1.90 boards. They look like this: Some notables vs a stock bluepill: 1) Castellated pins with flat underside for use as a module 2) 3 LEDs R/G/B (vs just the G for a bluepill) 3) Clone of ST's peripherals 4) over clockable to 256Mhz (spec is 216Mhz) (original STM32F103CB is 72Mhz) 5) 32K of ram. But, via secret regs, 97K(!) 6) top and bottom debug pads, top for JLINK, bottom, legacy STLINK SWD 7) USB C vs USB mini 8) BOOT as a button vs jumper 9) 2 12bit DACs (STM32F103CB's don't have that) 10) QSPI (hidden support) 11) Undocumented crypto block from MegaHunt (includes: AES/DES/3DES/SHA/SM[1,3,4,7]) Clocking As mentioned 256Mhz is possible. One Q is how do they...

Ada on a $2 eBay 'Bluepill' board (STM32F103C8T6)

For about $2 a 'bluepill' board can be obtained from eBay. Taking its name from the PCB patina this small board is used in the Arduino community. The SoC itself per ST's early docs on it was 64k flash and 20k data, that said, all STM32F103C8's you buy nowadays are 128k flash. The CPU is a Cortex-M3 which can be run at 72Mhz maximum. There is a good website that shows the schematic and pinout of the bluepill: http://wiki.stm32duino.com/index.php?title=Blue_Pill If you are an Arduino programmer, the link above will take you where you want to go. But suppose you wanted to try programming and using the bluepill a different way? Well that is what this blog entry is about. An Ada port was done via AdaCores Ada_Drivers_Library and the Libre GNAT toolchain to the bluepill. This is preliminary work but it is able to generate working code that the author already is using as of yesterday (a garage parking measurement sensor).  The port of the library is derivative, ...

The STM32MP257F-EV1

 This is the follow on to the STM32MP1 series. This time a dual core Cortex-A35 a Cortex-M33 and a Cortex-M0+. As shipped, they provide a 16G micro SD card with Linux on it. That card is partitioned with a lot of odd small partitions. The important ones are at the end, p10 and p11. Unfortunately p10, the / partition is only 4G so immediately there is a storage crisis when you start populating the usual tools. A quick dd from that card to a 256G card I had lying around and we now have a start of something useful. Next is to run gparted on my RPi5 and first move p11 which is /usr/local to 1MiB from the end. Don't leave that as 0 or the move will fail. Once moved, you can resize p10 to be 200+G. Now we have some useful space. I added a user with sudoers privs. There is no date/time setup when it boots, that needs to get rectified with a ntp callout.  Now... there is no C compiler or binutils. binutils got installed. Lots of apt update -> apt install xyz's. Here is an interesti...