This builds on the example Simple BLE and adds support for reading configuration data out of the User Information Configuration Registers. Download the example BLEUICR.zip which contains a readme describing each file in the package.
User Information Configuration Registers
The User Information Configuration Registers (UICR) is an area of flash separate from where the application code is stored within which various configuration data can be stored. In the previous example Simple BLE, the ID of the device (NSD123) was hardcoded into the application code. This is OK for a one off device but if there are multiple devices all using the same application code then it is not really satisfactory to have to recompile the code before flashing each device. Using the UICR registers gets away from this.
On the nRF5 devices that these examples have been built for, the UICR registers start at address 0x10001000. The first 128 bytes are reserved for Nordic (so not really customer registers). The area we can use is 128 bytes long and starts at address 0x10001080.
Flashing Configuration data to the UICR
The RPi SWD Programmer used throughout these examples is capable of reading JSON formatted configuration data files and flashing them to the UICR. This example contains the configuration file UICR.json which contains the following configuration data.
{
"SerialNumber":
{
"addr":0x10001080,
"str":"QQQ123",
},
"LEDOnPeriodMs":
{
"addr":0x10001088,
"u16":200,
},
"LEDOffPeriodMs":
{
"addr":0x1000108A,
"u16":0x1F4,
}
}
Each item in the configuration file has an address and a typed value to store at that address. In this example there is:
- A string “QQQ123” at address 0x10001080.
- A 16 bit unsigned integer (u16) with a value of 200 at address 0x10001088.
- A 16 bit unsigned integer (u16) with a value of 0x1F4 (500 decimal) at address 0x1000108A
This can be flashed to the microcontroller using the command:
C:\Projects\BLEUICR> "C:\Program Files\NoSMD\SWorD\bin\SWorDProgrammer.exe" -program:UICR.json -probe:rpi4programmer -pagesize:4096
Accessing the UICR from Application Code
It is straightforward to access the UICR data in the application code. Define a structure that matches how the configutation data is stored in flash and then simply memcpy it into the structure.
Numerical data is big endian.
//
// Define a structure to hold the configuration items
// Use pragma pack so the organisation of the structure exactly matches
// how the data is held in flash
//
#define SERIAL_NUMBER_LEN 6
#define SERIAL_NUMBER_FIELD_LEN 8
#pragma pack(push,1)
typedef struct
{
char m_SerialNumber[SERIAL_NUMBER_FIELD_LEN];
uint16_t m_LEDOnTimeMS;
uint16_t m_LEDOffTimeMS;
} UICRData;
#pragma pack(pop)
bool IsBigEndian();
#define BigEndianToNative32(val) (IsBigEndian() ? val : __REV(val))
#define BigEndianToNative16(val) (IsBigEndian() ? val : __REV16(val))
//
// Determines the endianness of the CPU
//
bool IsBigEndian()
{
static bool haveDeterminedEndian = false;
static bool isBigEndian = false;
if(!haveDeterminedEndian)
{
union { uint8_t c[4]; uint32_t i; } data;
data.i = 0x12345678;
isBigEndian = (data.c[0] == 0x78) ? false : true;
haveDeterminedEndian = true;
}
return isBigEndian;
}
//
// Function to load the config data from the UICR
//
void LoadUICR(UICRData* pAppConfig)
{
const uint32_t UICRBaseAddress = 0x10001000;
const uint32_t UICRCustomerBase = (UICRBaseAddress + 0x80);
memcpy(pAppConfig,(uint8_t*)UICRCustomerBase, sizeof(AppConfig));
pAppConfig->m_SerialNumber[SERIAL_NUMBER_LEN] = '\0';
pAppConfig->m_LEDOnTimeMS = BigEndianToNative16(pAppConfig->m_LEDOnTimeMS);
pAppConfig->m_LEDOffTimeMS = BigEndianToNative16(pAppConfig->m_LEDOffTimeMS);
}
Building and Flashing the Program
Any toolchain/programmer can be used for these steps. All the examples here are built using make and gcc. The binary is flashed using the Raspberry Pi networked programmer. See here for how to set up make, gcc and the Raspberry Pi networked programmer.
Building
From the terminal type:
C:\Projects\BLEUICR> "c:\Program Files (x86)\GnuWin32\bin\make.exe" -f makefile CONFIG=Debug all
If there are no errors then the binary bleuicr.elf should be output to the sub-folder bin\debug
Flashing the Binary to the Microcontroller
Hooking up the Programmer to the Microcontroller
See here for how to connect the programmer to the microcontroller.
Flashing
From a terminal type to flash both the softdevice (bluetooth stack), the application code and the config to the microcontroller:
C:\Projects\BLEUICR> "C:\Program Files\NoSMD\SWorD\bin\SWorDProgrammer.exe" -program:C:\SDK\NordicSDK\nRF5_SDK_17.0.0_9d13099\components\softdevice\s132\hex\s132_nrf52_7.0.1_softdevice.hex,bin\debug\bleuicr.elf,UICR.json -probe:rpi4programmer -pagesize:4096
Attempting to connect to rpi4programmer on 192.168.0.26::33332...
Connected to rpi4programmer on 192.168.0.26::33332...
Progress 100%
Completed with success
C:\Projects\BLEUICR>
Testing
The easiest way to test is to just print out each of the configuration items over SWO.
Initialising saadc...
Loaded configuration from UICR
Device serial number: QQQ123
LED on period: 200
LED off period: 500
Initialise BLE
Change the configuration file UICR.json and only reflash it to see how the operation of the app changes without changing the application code. To just reflash the configuration data.
C:\Projects\BLEUICR> "C:\Program Files\NoSMD\SWorD\bin\SWorDProgrammer.exe" -program:UICR.json -probe:rpi4programmer -pagesize:4096
If you change the serial number field you may have to restart your mobile app in order to see the new name. In some circumstances, the mobile phones bluetooth stack caches the name and you also need to restart bluetooth on the phone to see the new name.
0 Comments