A board support package for the LPC4088 Display Module.
Dependencies: DM_HttpServer DM_USBHost
Dependents: lpc4088_displaymodule_emwin lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI ... more
Fork of DMSupport by
Revision 2:887c6b45e7fa, committed 2014-12-02
- Comitter:
- embeddedartists
- Date:
- Tue Dec 02 15:21:18 2014 +0000
- Parent:
- 1:2846fb4d6435
- Child:
- 3:2fa7755f2cef
- Commit message:
- Added RTOS-safe logger (RtosLog). Switched USBHost library so that it works in an RTOS setting. Modified the FAT file system to work in an RTOS setting.
Changed in this revision
--- a/DMBoard.cpp Fri Nov 21 11:46:48 2014 +0000 +++ b/DMBoard.cpp Tue Dec 02 15:21:18 2014 +0000 @@ -26,6 +26,20 @@ * Defines and typedefs *****************************************************************************/ +#if defined(DM_BOARD_DISABLE_STANDARD_PRINTF) +class DevNull : public Stream { + +public: + DevNull(const char *name=NULL) : Stream(name) {} + +protected: + virtual int _getc() {return 0;} + virtual int _putc(int c) {return c;} +}; + +static DevNull null("null"); +#endif + /****************************************************************************** * Local variables *****************************************************************************/ @@ -56,10 +70,12 @@ DMBoard::~DMBoard() { +#if defined(DM_BOARD_USE_TOUCH) if (_touch != NULL) { delete _touch; _touch = NULL; } +#endif } DMBoard::BoardError DMBoard::readConfiguration() @@ -72,16 +88,16 @@ mem.powerDown(); #if 0 uint8_t* p = buff; - printf("\n-------\nBEFORE:\n-------\n"); + _logger.printf("\n-------\nBEFORE:\n-------\n"); for (int i = 0; i < 63; i++) { for (int j = 0; j < 4; j++) { - printf("0x%04x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + _logger.printf("0x%04x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7], p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15]); p += 16; } - printf("\n"); + _logger.printf("\n"); } // find first non-zero page and write to that @@ -94,7 +110,7 @@ } } if (zeroPage) { - printf("Will fill page 0x%04x (%d) with 0x00..0x3f\n", page, page); + _logger.printf("Will fill page 0x%04x (%d) with 0x00..0x3f\n", page, page); p = buff; for (int i = 0; i < mem.pageSize(); i++) { *p++ = i; @@ -103,16 +119,16 @@ memset(buff, 0, mem.memorySize()); mem.read(0, 0, buff, mem.memorySize()); p = buff; - printf("\n-------\nAFTER:\n-------\n"); + _logger.printf("\n-------\nAFTER:\n-------\n"); for (int i = 0; i < 63; i++) { for (int j = 0; j < 4; j++) { - printf("0x%04x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + _logger.printf("0x%04x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7], p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15]); p += 16; } - printf("\n"); + _logger.printf("\n"); } break; } @@ -199,6 +215,17 @@ _led3 = 0; _led4 = 0; + // Make sure that the logger is always initialized even if + // other initialization tasks fail + _logger.init(); + +#if defined(DM_BOARD_DISABLE_STANDARD_PRINTF) + // Kill all ouput of calls to printf() so that there is no + // simultaneous calls into the non-thread-safe standard libraries. + // User code should use the RtosLogger anyway. + freopen("/null", "w", stdout); +#endif + #if defined(DM_BOARD_USE_QSPI) && !defined(DM_BOARD_USE_QSPI_FS) if (SPIFI::instance().init() != SPIFI::Ok) { err = SpifiError; @@ -206,14 +233,6 @@ } #endif -#if defined(DM_BOARD_USE_FAST_UART) - // This works because both the default serial (used by printf) and the s instance - // (used by s.printf) would use the same underlying UART code so setting the baudrate - // in one affects the other. - Serial s(USBTX, USBRX); - s.baud(115200); -#endif - readConfiguration(); #if defined(DM_BOARD_USE_DISPLAY) @@ -240,19 +259,19 @@ return err; } -void DMBoard::setLED(int led, bool on) +void DMBoard::setLED(Leds led, bool on) { switch(led) { - case 1: + case Led1: _led1 = (on ? 0 : 1); break; - case 2: + case Led2: _led2 = (on ? 0 : 1); break; - case 3: + case Led3: _led3 = (on ? 1 : 0); break; - case 4: + case Led4: _led4 = (on ? 1 : 0); break; }
--- a/DMBoard.h Fri Nov 21 11:46:48 2014 +0000 +++ b/DMBoard.h Tue Dec 02 15:21:18 2014 +0000 @@ -19,6 +19,7 @@ #include "mbed.h" #include "dm_board_config.h" +#include "RtosLog.h" #if defined(DM_BOARD_USE_MCI_FS) #include "MCIFileSystem.h" @@ -52,8 +53,11 @@ */ class DMBoard { public: - enum Constants { - NumLEDs = 4, + enum Leds { + Led1, + Led2, + Led3, + Led4, }; enum BoardError { @@ -79,7 +83,7 @@ */ BoardError init(); - void setLED(int led, bool on); + void setLED(Leds led, bool on); void buzzer(float value); bool buttonPressed(); @@ -91,6 +95,7 @@ friend class Display; #endif + RtosLog* logger() { return &_logger; } private: @@ -113,6 +118,8 @@ DigitalOut _led3; DigitalOut _led4; + RtosLog _logger; + explicit DMBoard(); // hide copy constructor DMBoard(const DMBoard&);
--- a/DM_FATFileSystem.lib Fri Nov 21 11:46:48 2014 +0000 +++ b/DM_FATFileSystem.lib Tue Dec 02 15:21:18 2014 +0000 @@ -1,1 +1,1 @@ -http://developer.mbed.org/users/embeddedartists/code/DM_FATFileSystem/#e9018c2396af +http://developer.mbed.org/users/embeddedartists/code/DM_FATFileSystem/#4b97221ac12e
--- a/DM_USBHost.lib Fri Nov 21 11:46:48 2014 +0000 +++ b/DM_USBHost.lib Tue Dec 02 15:21:18 2014 +0000 @@ -1,1 +1,1 @@ -http://developer.mbed.org/users/embeddedartists/code/DM_USBHost/#a4c606c0439d +http://developer.mbed.org/users/embeddedartists/code/DM_USBHost/#aa2fd412f1d3
--- a/Display/Display.cpp Fri Nov 21 11:46:48 2014 +0000 +++ b/Display/Display.cpp Tue Dec 02 15:21:18 2014 +0000 @@ -18,6 +18,7 @@ #include "Display.h" #include "DMBoard.h" +#if defined(DM_BOARD_USE_DISPLAY) /****************************************************************************** * Defines and typedefs @@ -611,3 +612,5 @@ LPC_LCD->UPBASE = (uint32_t)buff; return (void*)old; } + +#endif //defined(DM_BOARD_USE_DISPLAY)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FileSystems/ff_rtos_helpers.cpp Tue Dec 02 15:21:18 2014 +0000 @@ -0,0 +1,197 @@ +/* + * Copyright 2014 Embedded Artists AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * Includes + *****************************************************************************/ + +#include "ff.h" +#include "mbed.h" +#include "rtos.h" + +/****************************************************************************** + * Defines and typedefs + *****************************************************************************/ + +/****************************************************************************** + * External global variables + *****************************************************************************/ + +/****************************************************************************** + * Local variables + *****************************************************************************/ + +/****************************************************************************** + * Global Functions + *****************************************************************************/ + +#if _FS_REENTRANT +/*------------------------------------------------------------------------*/ +/* Create a Synchronization Object */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount function to create a new +/ synchronization object, such as semaphore and mutex. When a zero is +/ returned, the f_mount function fails with FR_INT_ERR. +*/ + +int ff_cre_syncobj ( /* TRUE:Function succeeded, FALSE:Could not create due to any error */ + BYTE vol, /* Corresponding logical drive being processed */ + _SYNC_t *sobj /* Pointer to return the created sync object */ +) +{ + int ret; + +// *sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */ +// ret = (*sobj != INVALID_HANDLE_VALUE); + +// *sobj = SyncObjects[vol]; /* uITRON (give a static sync object) */ +// ret = 1; /* The initial value of the semaphore must be 1. */ + +// *sobj = OSMutexCreate(0, &err); /* uC/OS-II */ +// ret = (err == OS_NO_ERR); + +// *sobj = xSemaphoreCreateMutex(); /* FreeRTOS */ +// ret = (*sobj != NULL); + + *sobj = new Mutex(); /* MBED RTOS */ +// *sobj = new Semaphore(1); /* MBED RTOS */ + ret = (*sobj != NULL); + + return ret; +} + + + +/*------------------------------------------------------------------------*/ +/* Delete a Synchronization Object */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount function to delete a synchronization +/ object that created with ff_cre_syncobj function. When a zero is +/ returned, the f_mount function fails with FR_INT_ERR. +*/ + +int ff_del_syncobj ( /* TRUE:Function succeeded, FALSE:Could not delete due to any error */ + _SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ +) +{ + BOOL ret; + +// ret = CloseHandle(sobj); /* Win32 */ + +// ret = 1; /* uITRON (nothing to do) */ + +// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */ +// ret = (err == OS_NO_ERR); + +// ret = 1; /* FreeRTOS (nothing to do) */ + + if (sobj != NULL) { /* MBED RTOS */ + free(sobj); + } + ret = 1; + + return ret; +} + + + +/*------------------------------------------------------------------------*/ +/* Request Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on entering file functions to lock the volume. +/ When a zero is returned, the file function fails with FR_TIMEOUT. +*/ + +int ff_req_grant ( /* TRUE:Got a grant to access the volume, FALSE:Could not get a grant */ + _SYNC_t sobj /* Sync object to wait */ +) +{ + int ret; + +// ret = (WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */ + +// ret = (wai_sem(sobj) == E_OK); /* uITRON */ + +// OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */ +// ret = (err == OS_NO_ERR); + +// ret = (xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); /* FreeRTOS */ + + ret = ((*((Mutex*)sobj)).lock(_FS_TIMEOUT) == osOK); /* MBED RTOS */ +// static volatile osThreadId lastid = Thread::gettid(); +// ret = ((*((Semaphore*)sobj)).wait(_FS_TIMEOUT) == 1); /* MBED RTOS */ + + return ret; +} + + + +/*------------------------------------------------------------------------*/ +/* Release Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on leaving file functions to unlock the volume. +*/ + +void ff_rel_grant ( + _SYNC_t sobj /* Sync object to be signaled */ +) +{ +// ReleaseMutex(sobj); /* Win32 */ + +// sig_sem(sobj); /* uITRON */ + +// OSMutexPost(sobj); /* uC/OS-II */ + +// xSemaphoreGive(sobj); /* FreeRTOS */ + + (*((Mutex*)sobj)).unlock(); /* MBED RTOS */ +// (*((Semaphore*)sobj)).release(); /* MBED RTOS */ +} + +#endif + + + + +#if _USE_LFN == 3 /* LFN with a working buffer on the heap */ +/*------------------------------------------------------------------------*/ +/* Allocate a memory block */ +/*------------------------------------------------------------------------*/ +/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE. +*/ + +void* ff_memalloc ( /* Returns pointer to the allocated memory block */ + UINT size /* Number of bytes to allocate */ +) +{ + return malloc(size); +} + + +/*------------------------------------------------------------------------*/ +/* Free a memory block */ +/*------------------------------------------------------------------------*/ + +void ff_memfree( + void* mblock /* Pointer to the memory block to free */ +) +{ + free(mblock); +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RtosLog.cpp Tue Dec 02 15:21:18 2014 +0000 @@ -0,0 +1,126 @@ +/* + * Copyright 2014 Embedded Artists AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed.h" +#include "RtosLog.h" +#include <cstdarg> + +/****************************************************************************** + * Defines and typedefs + *****************************************************************************/ + + +/****************************************************************************** + * Local variables + *****************************************************************************/ + +/****************************************************************************** + * Private Functions + *****************************************************************************/ + +void RtosLog::logTask(void const* args) +{ + RtosLog* instance = (RtosLog*)args; + + while (true) { + osEvent evt = instance->_queue.get(); + if (evt.status == osEventMessage) { + message_t *message = (message_t*)evt.value.p; + if (message->ptr != NULL) { + instance->_serial.printf(message->ptr); + free(message->ptr); + } else { + instance->_serial.printf(message->msg); + } + + instance->_mpool.free(message); + + // Increase the number of available messages in the pool + instance->_sem.release(); + } + } +} + +/****************************************************************************** + * Public Functions + *****************************************************************************/ + +RtosLog::RtosLog() : + _sem(NumMessages), _serial(USBTX, USBRX), _thr(NULL) +{ +#if defined(DM_BOARD_USE_FAST_UART) + // This works because both the default serial (used by printf) and the s instance + // (used by s.printf) would use the same underlying UART code so setting the baudrate + // in one affects the other. + _serial.baud(115200); +#endif +} + +RtosLog::~RtosLog() +{ + if (_thr != NULL) { + _thr->terminate(); + delete _thr; + _thr = NULL; + } +} + +void RtosLog::init() +{ + if (_thr == NULL) { + _thr = new Thread(&RtosLog::logTask, this); + } +} + +int RtosLog::printf(const char* format, ...) +{ + // The pool has no "wait for free message" so we use a Sempahore + // to keep track of the number of free messages and, if needed, + // block the caller until a message is free + _sem.wait(); + + // Allocate a null terminated message. Will always succeed due to + // the semaphore above + message_t *message = _mpool.calloc(); + + // Write the callers formatted message + std::va_list args; + va_start(args, format); + int ret = vsnprintf(message->msg, MessageLen, format, args); + va_end(args); + + // If the entire message could not fit in the preallocated buffer + // then allocate a new one and try again. + if (ret > MessageLen) { + message->ptr = (char*)malloc(ret + 1); + if (message->ptr != NULL) { + va_start(args, format); + ret = vsnprintf(message->ptr, ret + 1, format, args); + va_end(args); + } + } + + // Send message + _queue.put(message); + + // Note that the Semaphore is not released here, that is done after + // the message has been processed and released into the pool by + // logTask() + //_sem.release(); + + return ret; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RtosLog.h Tue Dec 02 15:21:18 2014 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright 2014 Embedded Artists AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RTOSLOG_H +#define RTOSLOG_H + +#include "mbed.h" +#include "rtos.h" +#include "dm_board_config.h" + +/** + * All threads can independantly call the printf function in the RtosLog class + * without risc of getting the output tangled up. + * + * The RtosLog class uses a Thread to process the messages one at a time. + */ +class RtosLog { +public: + enum Constants { + MessageLen = 80, + NumMessages = 16, + }; + + RtosLog(); + ~RtosLog(); + + /** Starts the logger thread + */ + void init(); + + int printf(const char* format, ...); + +private: + + typedef struct { + char* ptr; /* Non-NULL if memory is allocated */ + char msg[MessageLen+1]; /* A counter value */ + } message_t; + + MemoryPool<message_t, NumMessages> _mpool; + Queue<message_t, NumMessages> _queue; + Semaphore _sem; + Serial _serial; + Thread* _thr; + + static void logTask(void const* args); +}; + +#endif + +
--- a/dm_board_config.h.txt Fri Nov 21 11:46:48 2014 +0000 +++ b/dm_board_config.h.txt Tue Dec 02 15:21:18 2014 +0000 @@ -31,6 +31,7 @@ // #define DM_BOARD_USE_XBEE #define DM_BOARD_USE_FAST_UART // #define DM_BOARD_USE_INT_EEPROM_WRITE +// #define DM_BOARD_DISABLE_STANDARD_PRINTF // #define DM_BOARD_USE_4_3_DISPLAY_TMP /* temporary while debugging */
--- a/mbed-rtos.lib Fri Nov 21 11:46:48 2014 +0000 +++ b/mbed-rtos.lib Tue Dec 02 15:21:18 2014 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/mbed_official/code/mbed-rtos/#02f5cf381388 +http://mbed.org/users/mbed_official/code/mbed-rtos/#c35dab33c427