Laird BL651 – nRF52810

Dieser Beitrag widmet sich um die zumindest mir bereiteten Fallstricke beim Arbeiten mit dem BL651 Modul. Die Informationen sollten sich auch auf die meisten anderen nRF52810 basierenden Module anwenden lassen.

Als erstes sollte man sich das SDK von nRF herunterladen. Dies gibt es in der Sparte `Sparte Software Development Kit` unter: https://www.nordicsemi.com/eng/Products/nRF52810

Das SDK entpackt man sich gemütlich z.B. ins home Verzeichnis. Nun brauchen wir den ARM Compiler, diesen installiert man unter Arch Linux ganz einfach mit Pacman:

sudo pacman -S arm-none-eabi-gcc arm-none-eabi-newlib

Damit man den nRF auch programmieren kann, ich verwende dazu einen J-Link, braucht man noch die nRF tools. Diese kann man sich unter Arch Linux mit yay installieren:

yay -S nrf5x-command-line-tools

Nun fehlt nur noch die Compiler Konfiguration im nRF SDK in der Datei `components/toolchain/gcc/Makefile.posix`:

GNU_INSTALL_ROOT ?= /usr/bin/
GNU_VERSION ?= 8.2.0
GNU_PREFIX ?= arm-none-eabi

Das SDK ist nun im Prinzip ready. Es fehlen jedoch noch die ein oder anderen Konfigurationen in den Examples. Möchte man z.B. das Beacon Example unter `examples/ble_peripheral/ble_app_beacon/pca10040e/s112` nutzen sind folgende Anpassungen notwendig:

Im Makefile müssen folgende Zeilen entfernt werden

CFLAGS += -DDEVELOP_IN_NRF52832
ASMFLAGS += -DDEVELOP_IN_NRF52832

In der sdk_config.h müssen folgende Parameter angepasst werden:

#define NRF_SDH_CLOCK_LF_SRC 0
#define NRF_SDH_CLOCK_LF_RC_CTIV 16
#define NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 2
#define NRF_SDH_CLOCK_LF_ACCURACY 1

Nun ist man nur noch von einem

make flash_softdevice && make flash

entfernt und das Example sollte auf dem nRF laufen 🙂

ESP8266 FLASH (/EEPROM)

esp_dev_kitEs geht weiter mit dem ESP8266. Die Grunddinge (softAP, station etc.) sitzen, wir kommen an den Punkt an welchem wir Daten speichern müssen. Daten können Zugangsdaten, Passwörter, Einstellungen, Stellungen etc. sein. Normalerweise nutzt man auf einer MCU dazu das altbekannte EEPROM. Dabei handelt es sich um einen persistenten Speicher, welcher seinen Inhalt im stromlosen Zustand behält. Auf dem ESP8266 haben wir jedoch kein solches EEPROM. Dafür haben wir einen schön grosssen FLASH Speicher. Unter anderem ist darauf Speicher für genau solche „User parameter“ reserviert. In diesem Artikel möchte ich einige Kernpunkte/Stolpersteine zur Verwendung davon nennen.

Hauptsächlich werden folgende 3 Funktionen genutzt. Diese sind im Espressif SDK vorhanden und in der API guide von Espressif beschrieben:

spi_flash_erase_sector (uint16 sec)
spi_flash_write (uint32 des_addr, uint32 *src_addr, uint32 size)
spi_flash_read(uint32 src_addr, uint32 * des_addr, uint32 size)

Der Nutzen der Befehle sollte im grossen und ganzen bereits durch dessen Namen klar sein.

Es wird von Sektoren und Adressen gesprochen. Woher weiss man nun wo man Daten schreiben kann/darf? Ganz einfach, es ist alles schön im Dokument „OTA Upgrade“ von Espressif beschrieben:512kb_esp8266
Anhand dieser Map können wir nun die Adressen/Sektoren berechnen. Interessant für uns ist der Block „User param“. Dieser umfasst 16KB, das heisst 4 Sektoren. Ein Sektor ist immer 4KB gross. Die erste Adresse berechnen wir nun wie folgt:

(64 + 176)  * 1024 = 0x3C000

Sektor ist demnach 0x3C (Adresse / 4096)

Am besten rechnet man sowas im Windows Taschenrechner, die Rechnung an sich ist Dezimal, danach um das Resultat in Hex zu haben auf Hexidezimal wechseln:

calc_0x3c

Ich arbeite im weiteren Verlauf jedoch mit dem zweiten User param Sektor. Dieser hat die Adresse 0x3D000 bzw. Sektor 0x3D. Berechnen kann man diesen indem man die Adresse für 4KB später berechnet.

Nun haben wir alle Infos um mit dem „arbeiten“ zu beginnen. Am besten fängt man mit einem simplen Programm wie folgt an:

unsigned char meinsatz[1024] = "Ich nutze ab jetzt den Flash Speicher für meine Daten!\n";
unsigned char meinflash[1024];

spi_flash_erase_sector(0x3D);
spi_flash_write(0x3D000, (uint32 *) meinsatz, sizeof(meinsatz));
spi_flash_read(0x3D000, (uint32 *) meinflash, sizeof(meinflash));
os_printf("%s", meinflash);

Das Programm löscht den Sektor (4KB) zuerst (zwingend!), danach wird der Speicher mit dem meinsatz beschrieben, dabei wird automatisch mit dem sizeof die Grösse ermittelt. Danach wird genau der Satz wieder geladen und mit printf ausgegeben.

So haben wir nun schon mal was. Schön ist das ganze jedoch natürlich noch nicht. Normalerweise hat man mehrere Parameter, z.B. einen Parameter für eine RGB Lampe Rot, Grün, Blau. Diese könnte man nur mit einem zusätzlichen (selbstgestrickten) handler trennen und organisieren. Das ganze lässt sich jedoch bereits ziemlich einfach und gut mit C Bordmitteln lösen. Dabei bauen wir uns sozusagen einen eigenen Datentyp. Diesen können wir mit bekannten Datentypen spicken (int, char, bool etc.).

struct parameter {
 char red, green, blue;
};

Diesen können wir nun wie folgt, ähnlich wie Variablen, nutzen.

struct parameter myparameter

myparameter.red = 120;
myparameter.green = 135;
myparameter.blue = 145;

Nun wird man sich fragen warum das für die Geschichte mit dem Flash gut sein soll. Ganz einfach: Wir können das ganze Struct in den Flash speichern und auch wieder holen 🙂

struct parameter myparameter
struct parameter myparameterfromflash
myparameter.red = 120;
myparameter.green = 135;
myparameter.blue = 145;

spi_flash_erase_sector(0x3D);
spi_flash_write(0x3D000, (uint32 *) &myparameter, sizeof(myparameter));
spi_flash_read(0x3D000, (uint32 *) myparameterfromflash, sizeof(myparameterfromflash));
os_printf("%s", myparameterfromflash.red);
os_printf("%s", myparameterfromflash.green);
os_printf("%s", myparameterfromflash.blue);

So können wir nun ganz Bequem und aufgeräumt Parameter zwischenspeichern, nutzen und vorallem auch persistens in den Flash speichern.

Ich habe dabei mit der NONOS SDK Version 1.5.2 gearbeitet. Konfiguiert wurde der Compiler auf den 512k Mode 0 ohne Boot.