EHAL

Embedded Hardware Abstraction Library


It is a library containing codes written in C with C++ wrapper for embedded devices that most MCUs have builtin.   Generally those devices are SPI, I2C, UART, TWI, etc... These are generic code independent of microprocessor architecture that can be ported to any type of microcontrollers.  This is a modern replacement of the arcane BSP (Board Support Package).  The library also contains other high level control code for add-on devices such as the IDM-LMX3208 series LED matrix multi-displays, SD card, etc... 

On second thought.  Initially I wanted to write C code with C++ wrapper.  The more generic code being added the more it is difficult to write it purely in C.  I ended up writing C++ class code in C.  ARM base MCU has begun taking over the low cost MCU realm with more memory resources.  Why should I pull my hairs off trying to support MCU with less resources.   For instant an LPC11Uxx with 64KB Flash, 8KB ram cost almost the same as an AT90USB with 16KB flash, 512 bytes ram.  Even Arduino is C++.  I will start refactoring this library be C++ based.   

One of the most important thing in multi-platform software development is the proper layout of the source tree, the directory tree structure.  The structure layout is simple.  Upper folder contains code generic to all folder under it.  The lower in the tree the more platform specific it is.  Often it is not easy to decide what goes where.  As long we keep in mind this structure the easier to find where things are.  Compiled binaries are always at the lowest level of the directory tree.

Source code on github : https://github.com/I-SYST/EHAL. Online doxygen documentation.
EHAL is being refactored.  The new library is https://github.com/IOsonata/IOsonata.  EHAL is still being maintained for bug fixes only.  New drivers will be implemented in the new IOsonata library with supports for more platforms and architectures.

The way the EHAL folder is structure is simple.  The deeper you go inside the more it is specific the the architecture or platform.  The parent folder contains all that is commonly available to the child fonder.  Which means, source file from child folder can access any source in the upper parent folder but not the other way around.  This is the way to keep the abstraction separated from implementation and easier to keep track of things.


/your_root     - Development root directory
 |-- external    - Contains downloaded SDKs from silicon vendors
 |   |-- CMSIS            - ARM CMSIS SDK for all ARM platform (download from ARM)
 |   |-- nRF5_SDK     - Latest Nordic SDK (download from nordicsemi.com)
 |   |-- KSDK             - Kinetis SDK
 |   |-- BSEC              - Bosch Sensortec Environmental Cluster (BSEC) Software
 |   |......
 |-- EHAL      - Put the EHAL here
 |   |-- include     - Generic include common to all platform
 |   |   |-- bluetooth   - Generic definition for Bluetooth
 |   |   |-- converters  - Generic definition for ADV, DAC, etc...
 |   |   |-- miscdev     - Generic definition for other non categorized devices
 |   |   |-- sensors      - Generic definition for al sort of sensors (environmental, motion, etc...)
 |   |-- src            - Generic implementation source common to all platform
 |   |
 |   |-- ARM - Cortex-M series based MCU
 |   |   |-- include    - Common include for all ARM platform
 |   |   |-- src           - Common source for all ARM platform
 |   |   |
 |   |   |-- NXP        - NXP ARM platform
 |   |   |   |-- LPC11xx - LPC11xx processor workspace
 |   |   |   |   |-- CMSIS
 |   |   |   |   |-- EHAL     - Embedded Hardware Abstraction Library project for NXP
 |   |   |   |   |   |-- include
 |   |   |   |   |   |-- src
 |   |   |   |   |-- exemples - Example code
 |   |   |   |-- LPC17xx - LPC17xx processor workspace
 |   |   |   |   |-- CMSIS
 |   |   |   |   |-- EHAL     - Embedded Hardware Abstraction Library project for NXP
 |   |   |   |   |   |-- include
 |   |   |   |   |   |-- src
 |   |   |   |   |-- exemples - Example code
 |   |   |
 |   |   |-- Nordic
 |   |   |   |-- nRF51 - nRF51 processor workspace
 |   |   |   |   |-- CMSIS   - static library of CMSIS system functions for nRF51
 |   |   |   |   |-- EHAL    - Embedded Hardware Abstraction Library project for Nordic
 |   |   |   |   |   |-- include
 |   |   |   |   |   |-- src
 |   |   |   |   |-- exemples - exemple projects
 |   |   |   |-- nRF52 - nRF52 processor workspace
 |   |   |   |   |-- CMSIS   - static library of CMSIS system functions for nRF52
 |   |   |   |   |-- EHAL    - Embedded Hardware Abstraction Library project for Nordic
 |   |   |   |   |   |-- include
 |   |   |   |   |   |-- src
 |   |   |   |   |-- exemples - exemple projects
 |   |   |
 |   |   |-- ST
 |   |   |
 |   |   |-- TI
 |   |   |   |-- CC3200
 |   |   |   |   |-- CMSIS
 |   |   |   |   |-- EHAL
 |   |   |   |   |   |-- include
 |   |   |   |   |   |-- src
 |   |   |   |   |-- exemples - Example code
 |   |   |
 |   |   |-- Freescale
 |   |   |   |-- MKL
 |   |   |   |   |-- CMSIS
 |   |   |   |   |-- EHAL
 |   |   |   |   |   |-- include
 |   |   |   |   |   |-- src
 |   |   |   |   |-- exemples - Example code
 |   |...
 |   |-- Linux
 |   |   |...
 |   |-- OSX
 |   |   |...
 |   |-- Win
 |   |   |...
 | ...


ARM CMSIS library


ARM development requires the CMSIS library.  The latest library can be downloaded from https://github.com/ARM-software/CMSIS_5.  Put the library under ARM folder of the development tree as shown above.  All core specifics are reference from the ARM CMSIS SDK.  All chip specifics are referenced to workspace CMSIS library.

Note : Require change to compile CMSIS_RTX with GCC.  There is a compile error about the use of r7 for Cortex-M0 in the file rt_CMSIS.c in function SVC_Call.  Just replace r7 by r6.

Coding practice


Other important things to remember when writing portable code :

- Avoid using conditional compilation as much as possible.  Use library instead.
- Pack all structures accordingly, use #pragma pack(n) or #pragma pack(push, n) / #pragma pack(pop) instead of compiler specific keyword such as __packed or __attribute__((__packed__)).  Those #pragma pack(...) are standard on most compilers a long long time ago.  Avoid at all costs doing ugly struct definition such as bellow :

typedef PACKED( struct
{
    float x;
    float y;
    float z;
}) ble_tms_gravity_t;

Instead do :

#pragma pack(push, 1)

typedef struct {
    float x;
    float y;
    float z;
ble_tms_gravity_t;

#pragma pack(pop)

 
- Use stdint types such as uint32_t... instead of some custom types like U32 or UINT32 ... 
- To use standard C++ bool type C, include "stdbool.h"
- Absolute must avoid using macro to define a function or variable.  It is a source of bug that you'd never expect.  See simple example bellow.  Keep macro strictly to define a constant.

#define min(x, y)     ((x) > (y) ? (y) : (x))

int a =5, b = 6, c;
c = min(5, 6);      // result c = 5, a = 5, b = 6
c = min(a++, b);    // result c = 6, a = 7, b = 6 but the intended result is c = 5, a = 6, b = 6

That is a common macro everyone is doing unconsciously.  Imagine when you put a whole function in a macro like that.   Which I have seen a lot in open source and many big name companies.  C99 and above has support for inline.  Use it instead to replace the macro.

static inline int min(x, y)   { return x > y ? y : x; }

c = min(a++, b);    // result c = 5, a = 6, b = 6



Generating automatic build number


There is a simple way to generate automatic build number using date.  The follow will work on OS X and Linux only.  It make use of system command date.  When you type date +"%Y%m%d" at the shell it will give a number yyymmdd.  Example 20150210.  The command is date +Format.  To use this.  Open project property, add a preprocessor macro as

BUILDNO=$$(date +"%Y%m%d")

Note : a space between 'date' and '+' is important.

Each time you compile BUILDNO will be defined as the current date.  Use format "%s" if you wish to use number of second elapsed since 1970 instead of current date.


Nordic nRF51/nRF52 requirements

The Nordic SDK needs to be downloaded and put into your workspace.  The SDK must be placed under folder nrf51_sdk.  Download the SDK zip format from nordic,  unzip it, rename it to nrf51_sdk, move it to the folder structured as above.  See nRF51 blog page for more on software development with nRF51 series

Support for TI CC3200  Wifi SoC is progressing well.  See CC3200 Page for details

No specific SDK require for NXP LPC series

Freescale has a big SDK.  Main issue, Flash security settings located at 0x400-0x410 of the code region.  Be careful, bad values in that area will result in processor lockup for good.





19 comments:

  1. Hello

    I am facing problem in programming nRF51822_xxAA chips.
    I built the OTA(Buttonless DFU Example) code in GCC using Embitz IDE.
    The code runs completely in nRF51-DK(having nRF51422_xxAC chip), But the code don't run in external Hardware(with nRF51822_xxAA chip).
    I reduced the firmware size by implementing the simple LED on/off function codes. But after flashing the SoftDevice code(S130 V2.0.1), the code stucks into nRF_delay_ms() function.

    Please suggest me what to do next to run the code.

    ReplyDelete
    Replies
    1. The xAA chip has only 16KB RAM compare to the xxAC which has 32KB. You need to edit the linker script .ld file to readjust the ram size

      Delete
  2. Hi Nguyen,

    I just received my IDAP-Link, but i just wondering if you can help me, I'm trying to connect a Ebyte E73 (NRF52832) using SWDIO, SWDCLK, VCC and GND but i've tried with many tools without success, also Keil.

    Thanks

    ReplyDelete
    Replies
    1. Hi, how does your board powered ? The VCC of your board must be connected to TVREF (pin 1) of the IDAP-Link. In Keil or any other IDE, select CMSIS-DAP as jtag tool.

      Delete
    2. To flash the nRF5x hex files without an IDE, download the IDAPnRFProg from https://sourceforge.net/projects/idaplinkfirmware/files/.

      Delete
  3. Hi, thanks for your help, i've changed VCC to TVREF but I can't connect it with keil, on Debug config show the IDAP-Link also with serial and firmware version, but on JTAG device chain (right side) show SWD/JTAG Communication failure.

    ReplyDelete
    Replies
    1. How does you board powered ?

      Delete
    2. Connection is as follow :

      IDAP -- nRF (self powered)
      TVREF -- VCC
      SWDIO -- SWDIO
      SWDCLK -- SWDCLK
      GND -- GND

      If you want to use 3.3V from the IDAP to power your board :

      IDAP -- nRF (powered by 3.3v from IDAP)
      3.3V -- VCC
      TVREF --VCC
      SWDIO -- SWDIO
      SWDCLK -- SWDCLK
      GND -- GND

      Delete
  4. Hi, I'm using the power from the IDAP, so connect IDAP 3.3v and TVREF to same VCC on my board ?

    ReplyDelete
    Replies
    1. Wowww finally, thank you very much, now i have another problem, keil show "Invalid ROM Table" message

      Delete
    2. makesure that you select the correct target device in Keil. First, lets try something to make sure the boards work. Have you downloaded the IDAPnRFPRog program ? From the command line shell, execute :

      IDAPnRFProg anyfirmware.hex

      Try the prebuild hex from the HRS example of the SDK.

      Delete
    3. Wonderful, I'm still trying with Keil, but with IDAPnRFProg test.hex works flawlessly. Really appreciate your help

      Delete
    4. Ok, here are a few things to check for Keil. In Debug select the CMSIS-DAP Debugger. There is a button 'Settings' beside it. Click on it. You will see a popup. On the left, in the CMSIS-DAP-JTAG/SW Adapter, you see a dropdown. You can select any or IDAP-Link. Make sure Port is SW selected. On the right 'SW Device, You should see the IDCode 0x2BA01477 ARM Coresight SW-DP. If you don't see any of those, it means Keil is not connected to the board

      Delete
    5. The CMSIS-DAP is now connected to Keil, now the issue is with keil when tried to download, show Insufficient RAM for Flash Algorithms ! I'm trying with the example app_blinky_c

      Delete
    6. You can change the settings for that based on the target device you are using. That RAM is the nRF RAM, not the jtag. Make sure you set the target FLASH & RAM with the correct values

      Delete
  5. Hi.

    I have just started taking over a nRF52 ARM based project. The project is seemingly using the (now deprecated) EHAL library, and while everything compiles fine, at linker time I get the error "... /arm-none-eabi/bin/ld.exe: cannot find -lEHAL"
    So I cloned EHAL from Github, and have looked around a bit, which leads to the following questions. Pardon if this is just a trivial newbie question ;-)

    Is EHAL code that you include in your own code at compile time, or is EHAL code that you compile first into a local library, for the given target platform, and then link to? (It seems to be the latter.)

    Is it enough to just build the library relevant for the target platform, or should the entire EHAL be built at top-level? However, there are no .cproject files at top level.

    When looking around for Eclipse .cproject files I found one at EHAL\ARM\Nordic\nRF52840\EHAL
    However when building that I get compile errors, for instance

    sensors/agm_invn_icm20948.cpp

    fails due to

    #include "Devices/Drivers/Icm20948/Icm20948.h"

    as there is not such folder Devices/Drivers anywhere.

    I sense I am missing something fundamental in understanding how this all should be setup and used. I have followed your nice instructions for the Eclipse setup, I should add. Could you perhaps enlighten me, or is there some more introduction or tutorial for EHAL you could point me towards?

    Thank you! - Henrik

    ReplyDelete
    Replies
    1. Hi, You need to compiles 2 libraries into a .a first (EAHL and CMSIS). Then your project will link. EHAL is a multi-arch lib. The projects to build is inside each target device. For nRF52 it would be in ARM/Nordic/nRF52/...
      The missing icm20948 is part of the driver that needs to be downloaded form invensense. There are link to download requires external drivers and where to put then in the README.md at the root of the repo.

      Delete
    2. Much appreciated Hoan, thank you! I will look into it.

      Delete