Close

Code Overview 6: Remote Memory Access

A project log for HEXABITZ - Modular Electronics for REAL

A new kind of electronic prototyping!

hexabitzHexabitz 04/03/2018 at 03:590 Comments

BOS offers a powerful remote memory read/write access functionality through specific Messages and APIs. This allows a module to access and modify almost any RAM or Flash memory location in another module in the array thus providing powerful synchronization and granular control.

BOS Variables

Typically, you will need a valid memory address to read a variable stored in RAM (e.g., 0x20000100) or Flash (e.g., 0x08000100). In order to simplify the process, BOS defines a set of RAM-based BOS Variables that you can use to easily exchange small amount of data across the array. BOS Variables can be addressed with easy-to-use virtual addresses (1 to N) without the need to know their actual RAM location. For example, you can link a float (or any other datatype) value to BOS Var 1 and access it from any other module in the array. There is a maximum number of bytes that each module reserve for BOS variables. It is defined in MAX_BOS_VARS preprocessor constant. If MAX_BOS_VARS=100, then you can define 100 1-byte variables, or 25 1-word variables and so forth.
The following examples demonstrate how to define BOS variables. Using the keyword volatile in front of a variable definition tells the compiler that this variable might change outside the program (e.g., by a remote module):

// LED state (ON/OFF), intensity and color (global or static if inside a function)                            
volatile bool state = true;                 
volatile uint8_t intensity = 50, color = WHITE;    

// Link to BOS variables (inside a function)    
AddBOSvar(FMT_BOOL, (uint32_t) &state);
AddBOSvar(FMT_UINT8, (uint32_t) &intensity);
AddBOSvar(FMT_UINT8, (uint32_t) &color);

The API AddBOSvar() accepts the following datatypes:

FMT_UINT8
FMT_INT8
FMT_UINT16
FMT_INT16
FMT_UINT32
FMT_INT32
FMT_FLOAT
FMT_BOOL

and returns the BOS variable index (or virtual address) or 0 if memory is full.
Note 1: BOS variables must be defined as global (e.g., outside a function) or static to ensure we do not reference a temporary variable within a function stack.
Note 2: When using direct Flash and RAM addresses, pay special attention to memory alignment. Cortex-M0 MCUs do not accept non-word aligned memory access, which results in a processor Hardfault.

Remote Read

Use the ReadRemoteVar() and ReadRemoteMemory() APIs to read a remote module BOS variable or memory location. The first one returns a pointer to the remote value as well as a pointer to the remote BOS variable format. The second API only returns a pointer to the remote value. The remote format here should be specified by the local module since a memory location can contain any datatype. Note that the returned pointers must be casted to the correct datatype before their addressed value can be read correctly. The following examples demonstrate the proper use of these APIs:

volatile float myremotevar = 0;
// Reading remote address 0x2000001c from Module 2 with FLOAT format and 1000ms timeout
myremotevar = *(float *)ReadRemoteMemory(2, 0x2000001c, FMT_FLOAT, 1000);

volatile bool mybool;
varFormat_t format1;
/* Reading remote BOS variable 1 from Module 2 with 100ms timeout. Remote format is requested and stored in format1. It can be used to cast the variable properly in case we don't know the format beforehand */
mybool = *(bool *)ReadRemoteVar(2, 1, &format1, 100);

Both read APIs will block until the read value is returned or timeout reached (in which case a NULL pointer is returned). If he requested remote BOS variable does not exist, the APIs return BOS_ERR_REMOTE_READ_NO_VAR.

Remote Write

The API WriteRemote() is used to write to both a remote memory location or BOS variable. Setting up the remoteAddress parameter to any value between 1 and MAX_BOS_VARS writes to a BOS variable while setting it up to a valid RAM or Flash location writes to this location. If the BOS variable does not exist, a new one will be created in the remote module. The remote format is always specified by the local module. The following examples demonstrate the API usage:

volatile bool mybool = true;
/* Writing the value of mybool to remote BOS variable 1 in Module 2 with a BOOL format and 0 timeout, i.e., skipping confirmation */
WriteRemote(2, (uint32_t) &mybool, 1, FMT_BOOL, 0);

volatile uint32_t mynum = 0x12ABCDEF;
/* Writing the value of mynum to remote address 0x08016000 in Module 2 with UINT32 format and 100 timeout */
WriteRemote(2, (uint32_t) &mynum, 0x08016000, FMT_UINT32, 100);

A remote write with non-zero timeout will block until a confirmation Message is received or timeout reached. A zero timeout disables sending a confirmation. The confirmation Message returns success (BOS_OK=0) or the following error codes:

Note: In order to write to an MCU Flash address, the address must contain 0xFFFFFFFF or the entire page (1024 bytes) must be erased beforehand. If you are aware of the consequences of this and still want to force erasing the page if needed, use the WriteRemoteForce() API.

Discussions