Has anyone tried to use Memory Pools and Mailboxes in this port? Here's my two questions:
-
I'm seeing some odd behavior in the mailboxes, particularly in the first pull from the mailbox. The data of the object pulled seems corrupted though I suspect it's some header information. Likely pilot error.
-
Also seeing "junk" at the top of every memory pool item allocated. Again, I think from reading the ChibiOS forums and documentation I think this is the pool header though some examples on the ChibiOS forums do not show this needing to be exlicitly defined in the memory structure.
Here's the code in question. Two small tasks delaying a second each, posting to the mailbox a seconds counter, and a third task picking it up and displaying it on an LCD. Pretty simple stuff. Notice I do a bit of error checking on the content to weed out the first mailbox data error.
Here's the structure definition for the mailbox/mempool data:
typedef struct {
int junk;
int thread;
unsigned long cnt;
} msgLCD;
Here's the RTOS code. Did not include header info and support functions to keep it short.:
#define MB_SIZE 6
#define TEAM_A_TITLE_LOC 0
#define TEAM_B_TITLE_LOC 16
#define TEAM_A_TITLE "Time A"
#define TEAM_B_TITLE "Time B"
#define TEAM_A_TIMER_H 7
#define TEAM_B_TIMER_H 16+TEAM_A_TIMER_H
#define TEAM_A_TIMER_M 10
#define TEAM_B_TIMER_M 16+TEAM_A_TIMER_M
#define TEAM_A_TIMER_S 13
#define TEAM_B_TIMER_S 16+TEAM_A_TIMER_S
#define ACTIVE_TEAM_A_LOC 15
#define ACTIVE_TEAM_B_LOC 16+ACTIVE_TEAM_A_LOC
#define ACTIVE_TEAM_INDICATOR "<"
const uint8_t LED_PIN = 13;
//const uint8_t servo_PIN = 9;
//Servo myServo;
SoftwareSerial mainLCD(2, 3);
static char buffer[sizeof(msgLCD)*MB_SIZE];
//MemoryPool pool;
static MEMORYPOOL_DECL(pool, sizeof(msgLCD)*MB_SIZE, NULL);
static MAILBOX_DECL(mbox, buffer, sizeof(buffer));
// align data, this depends on your compiler. this works for GCC
msgLCD data[MB_SIZE] __attribute__((aligned(sizeof(stkalign_t))));
String formatTwoDigits(unsigned int iVal) {
String sTens = "";
sTens += iVal / 10;
String sOnes = "";
sOnes += iVal % 10;
return sTens+sOnes;
}
void printTime(unsigned int h, unsigned int m, unsigned int s, int team) {
int rowLoc = TEAM_A_TIMER_H;
if (team == 2) {
rowLoc = TEAM_B_TIMER_H;
}
setLCDCursor(&mainLCD, rowLoc);
mainLCD.print(formatTwoDigits(h));
mainLCD.print(":");
mainLCD.print(formatTwoDigits(m));
mainLCD.print(":");
mainLCD.print(formatTwoDigits(s));
}
//------------------------------------------------------------------------------
// Simulated Worker Thread 1
static WORKING_AREA(waThread1, 64);
static msg_t Thread1(void *arg) {
int counter = 0;
while (TRUE) {
chThdSleepMilliseconds(1000);
counter++;
//grab a memory pool item
msgLCD *msg = (msgLCD *)chPoolAlloc(&pool);
if (msg != NULL) {
msg->thread = 1;
msg->cnt = counter;
// Here we'll send something to the LCD thread
chMBPost(&mbox, (msg_t)msg, TIME_INFINITE);
}
}
return 0;
}
//------------------------------------------------------------------------------
// Simulated Worker Thread 2
static WORKING_AREA(waThread2, 64);
static msg_t Thread2(void *arg) {
int counter = 0;
while (TRUE) {
chThdSleepMilliseconds(1000);
counter++;
//grab a memory pool item
msgLCD *msg = (msgLCD *)chPoolAlloc(&pool);
if (msg != NULL) {
msg->thread = 2;
msg->cnt = counter;
// Here we'll send something to the LCD thread
chMBPost(&mbox, (msg_t)msg, TIME_INFINITE);
}
}
return 0;
}
//------------------------------------------------------------------------------
// LCD Thread - This thread waits on a Mailbox (FIFO Queue) and depending on who
// sent the message, displays in the proper quadrant of the LCD
static WORKING_AREA(waLCDThread, 64);
static msg_t LCDThread(void *arg) {
msg_t msg1;
msgLCD msg2;
unsigned int teamA_h = 0, teamA_m = 0, teamA_s = 0;
unsigned int teamB_h = 0, teamB_m = 0, teamB_s = 0;
static boolean t1s = FALSE;
static boolean t2s = FALSE;
static boolean LED_state = FALSE;
clearDisplay(&mainLCD);
setLCDCursor(&mainLCD, TEAM_A_TITLE_LOC);
mainLCD.print(TEAM_A_TITLE);
setLCDCursor(&mainLCD, TEAM_A_TIMER_H);
mainLCD.print("00:00:00");
setLCDCursor(&mainLCD, TEAM_B_TITLE_LOC);
mainLCD.print(TEAM_B_TITLE);
setLCDCursor(&mainLCD, TEAM_B_TIMER_H);
mainLCD.print("00:00:00");
while (TRUE) {
// Wait on a message from the working threads to display
msg1 = chMBFetch(&mbox, (msg_t *)&msg2, TIME_INFINITE);
if (msg1 == RDY_OK) {
LED_state = !LED_state;
digitalWrite(LED_PIN, LED_state);
// If we get here, we have a message
if (msg2.thread == 1) {
setLCDCursor(&mainLCD, TEAM_A_TIMER_H);
t1s = !t1s;
teamA_h = msg2.cnt / 3600;
teamA_m = (msg2.cnt % 3600) / 60;
teamA_s = msg2.cnt % 60;
printTime(teamA_h, teamA_m, teamA_s, msg2.thread);
}
if (msg2.thread == 2) {
setLCDCursor(&mainLCD, TEAM_B_TIMER_H);
t2s = !t2s;
teamB_h = msg2.cnt / 3600;
teamB_m = (msg2.cnt % 3600) / 60;
teamB_s = msg2.cnt % 60;
printTime(teamB_h, teamB_m, teamB_s, msg2.thread);
}
} else {
Serial.print("Fetch Status: ");
Serial.println(msg1);
}
// Now we have to free the memory pool object
chPoolFree(&pool, (void *)&msg2);
}
return 0;
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
mainLCD.begin(9600);
pinMode(LED_PIN, OUTPUT);
// myServo.attach(servo_PIN);
// myServo.write(10);
chThdSleepMilliseconds(15);
// Here we can muck with the LCD because nothing in the RTOS system is initialized
clearDisplay(&mainLCD);
setLCDCursor(&mainLCD, 2); // Set cursor to the 3rd spot, 1st line
mainLCD.print("Initializing");
setLCDCursor(&mainLCD, 16); // Set the cursor to the beginning of the 2nd line
mainLCD.print("RTOS System...");
// From here on, only the LCD thread should handle this hardware.
halInit();
chSysInit();
// add each element to the pool
// this is the least obvious part of the process, as far as my experience went
for(int i=0; i <= MB_SIZE; i++) {
chPoolFree(&pool, &data[i]);
}
//Initialize the mailbox
chMBInit(&mbox, (msg_t *)buffer, MB_SIZE);
chMBReset(&mbox);
delay(2000);
msg_t msg1;
msgLCD msg, msg2;
chMBPost(&mbox, (msg_t)&msg, TIME_INFINITE);
chMBPost(&mbox, (msg_t)&msg2, TIME_INFINITE);
chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 2, Thread1, NULL);
chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO + 1, Thread2, NULL);
chThdCreateStatic(waLCDThread, sizeof(waLCDThread), NORMALPRIO + 3, LCDThread, NULL);
while(TRUE){}
}
void loop() {
// never called
}