From 58a90f40cabdae1696f290dcc16cbbef9c081f02 Mon Sep 17 00:00:00 2001 From: bunnie Date: Tue, 31 May 2016 10:48:08 +0000 Subject: [PATCH] performance optimization, memory optimization --- orchard/Makefile | 10 +- orchard/analog.c | 4 +- orchard/chconf.h | 4 +- orchard/dv-serialmode.c | 53 +++++---- orchard/dv-serialmode.h | 1 + orchard/halconf.h | 2 +- orchard/main.c | 144 +++++++++++++----------- orchard/orchard-events.h | 8 +- os/hal/ports/KINETIS/KL02x/serial_lld.c | 6 + os/hal/src/serial.c | 2 +- 10 files changed, 137 insertions(+), 97 deletions(-) diff --git a/orchard/Makefile b/orchard/Makefile index 539cced29..4ec0ed4ed 100644 --- a/orchard/Makefile +++ b/orchard/Makefile @@ -5,7 +5,7 @@ # Compiler options here. ifeq ($(USE_OPT),) - USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16 -nostdlib -fstack-protector + USE_OPT = -O3 -ggdb -fomit-frame-pointer -falign-functions=16 -nostdlib -fstack-protector endif # C specific options here (added to USE_OPT). @@ -43,6 +43,12 @@ ifeq ($(USE_VERBOSE_COMPILE),) USE_VERBOSE_COMPILE = no endif +# If enabled, this option makes the build process faster by not compiling +# modules not used in the current configuration. +ifeq ($(USE_SMART_BUILD),) + USE_SMART_BUILD = yes +endif + # # Build global options ############################################################################## @@ -54,7 +60,7 @@ endif # Stack size to be allocated to the Cortex-M process stack. This stack is # the stack used by the main() thread. ifeq ($(USE_PROCESS_STACKSIZE),) - USE_PROCESS_STACKSIZE = 0x500 + USE_PROCESS_STACKSIZE = 196 endif # Stack size to the allocated to the Cortex-M main/exceptions stack. This diff --git a/orchard/analog.c b/orchard/analog.c index 7a48a1442..d545542fa 100644 --- a/orchard/analog.c +++ b/orchard/analog.c @@ -53,7 +53,7 @@ static void adc_temperature_end_cb(ADCDriver *adcp, adcsample_t *buffer, size_t celcius = 25000 - delta; chSysLockFromISR(); - chEvtBroadcastI(&adc_celcius_event); + // chEvtBroadcastI(&adc_celcius_event); chSysUnlockFromISR(); } @@ -101,7 +101,7 @@ static void adc_mic_end_cb(ADCDriver *adcp, adcsample_t *buffer, size_t n) { } chSysLockFromISR(); - chEvtBroadcastI(&adc_mic_event); + // chEvtBroadcastI(&adc_mic_event); chSysUnlockFromISR(); } diff --git a/orchard/chconf.h b/orchard/chconf.h index 7556cc2f2..621cf168d 100644 --- a/orchard/chconf.h +++ b/orchard/chconf.h @@ -100,7 +100,7 @@ * does not spawn the idle thread. The application @p main() * function becomes the idle thread and must implement an * infinite loop. */ -#define CH_CFG_NO_IDLE_THREAD FALSE +#define CH_CFG_NO_IDLE_THREAD TRUE /** @} */ @@ -267,7 +267,7 @@ * * @note The default is @p TRUE. */ -#define CH_CFG_USE_QUEUES FALSE +#define CH_CFG_USE_QUEUES TRUE /** * @brief Core Memory Manager APIs. diff --git a/orchard/dv-serialmode.c b/orchard/dv-serialmode.c index cc31692fa..1290911c6 100644 --- a/orchard/dv-serialmode.c +++ b/orchard/dv-serialmode.c @@ -3,6 +3,7 @@ #include "orchard.h" #include "orchard-shell.h" +#include "orchard-events.h" #include "oled.h" #include "gfx.h" @@ -12,7 +13,7 @@ #define MAX_ROWS 4 #define TEXT_LEN (MAX_COLS * MAX_ROWS) static char text_buffer[TEXT_LEN]; -static uint8_t write_ptr = 0; +static int8_t write_ptr = 0; uint8_t isprint_local(char c) { return ((c >= ' ' && c <= '~') ? 1 : 0); @@ -26,10 +27,11 @@ int find_printable_window(void) { // starting from the last written character, search backwards... while( chars_searched < TEXT_LEN ) { - if( (text_buffer[cur_ptr] == '\n') || (text_buffer[cur_ptr] == '\r' ) ) { + if( text_buffer[cur_ptr] == '\n' ) { // chprintf(stream, "n"); num_lines++; - if( num_lines == (MAX_ROWS+1) ) { // forward back over the final newline we found + // MAX_ROWS+1 if you want to show the current incoming line too + if( num_lines == (MAX_ROWS+2) ) { // forward back over the final newline we found cur_ptr++; cur_ptr %= TEXT_LEN; break; } @@ -46,7 +48,8 @@ int find_printable_window(void) { // chprintf(stream, "c"); num_lines++; chars_since_newline = 0; - if( num_lines >= (MAX_ROWS+1) ) { + // MAX_ROWS+1 if you want to show the current incoming line too + if( num_lines >= (MAX_ROWS+2) ) { cur_ptr++; cur_ptr %= TEXT_LEN; break; } @@ -69,7 +72,7 @@ int find_printable_window(void) { return cur_ptr; } -void update_screen(void) { +void updateSerialScreen(void) { coord_t width; coord_t font_height; font_t font; @@ -96,7 +99,7 @@ void update_screen(void) { if( cur_char == write_ptr ) break; - if( (text_buffer[cur_char] == '\n') || (text_buffer[cur_char] == '\r') ) { + if( text_buffer[cur_char] == '\n' ) { str_to_render[i] = ' '; cur_char++; i++; chars_processed++; cur_char %= TEXT_LEN; @@ -126,7 +129,7 @@ void update_screen(void) { void dvInit(void) { int i; for( i = 0; i < TEXT_LEN; i++ ) { - text_buffer[i] = ' '; // init with whitespace + text_buffer[i] = ' '; // init with whitespace, use something else for debugging hints } text_buffer[TEXT_LEN-1] = '\n'; // simulate final newline write_ptr = 0; @@ -134,18 +137,30 @@ void dvInit(void) { void dvDoSerial(void) { char c; - - if(chSequentialStreamRead((BaseSequentialStream *) stream, (uint8_t *)&c, 1) == 0) - return; - - // chSequentialStreamPut((BaseSequentialStream *)stream, c); // local echo to tx - - text_buffer[write_ptr] = c; + int8_t prev_ptr; + + while(TRUE) { + prev_ptr = write_ptr - 1; + if( prev_ptr == -1 ) + prev_ptr = TEXT_LEN - 1; + + if(chSequentialStreamRead((BaseSequentialStream *) stream, (uint8_t *)&c, 1) == 0) + return; // we keep on running until the buffer is empty + + if( c == '\r' ) + c = '\n'; + + // if CRLF, eat multiple CRLF + if( c == '\n' ) { + if( text_buffer[prev_ptr] == '\n' ) + return; + } + + text_buffer[write_ptr] = c; - write_ptr++; - write_ptr %= TEXT_LEN; - text_buffer[write_ptr] = ' '; // rule: current spot we're pointing to for write cannot be a newline + write_ptr++; + write_ptr %= TEXT_LEN; + text_buffer[write_ptr] = ' '; // rule: current spot we're pointing to for write cannot be a newline + } - update_screen(); - } diff --git a/orchard/dv-serialmode.h b/orchard/dv-serialmode.h index 9cecbc6c8..1d21ff1a4 100644 --- a/orchard/dv-serialmode.h +++ b/orchard/dv-serialmode.h @@ -1,2 +1,3 @@ void dvInit(void); void dvDoSerial(void); +void updateSerialScreen(void); diff --git a/orchard/halconf.h b/orchard/halconf.h index 9085c5491..a53cc98da 100644 --- a/orchard/halconf.h +++ b/orchard/halconf.h @@ -284,7 +284,7 @@ * buffers. */ #if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) -#define SERIAL_BUFFERS_SIZE 16 +#define SERIAL_BUFFERS_SIZE 32 #endif /*===========================================================================*/ diff --git a/orchard/main.c b/orchard/main.c index 33871f217..964005696 100644 --- a/orchard/main.c +++ b/orchard/main.c @@ -37,8 +37,12 @@ #include "kl02x.h" struct evt_table orchard_app_events; -event_source_t ta_update_event; -event_source_t adc_celcius_event; +event_source_t refresh_event; +event_source_t serial_event; +uint8_t serial_init = 0; + +static virtual_timer_t led_vt; +static virtual_timer_t refresh_vt; static void mode_cb(EXTDriver *extp, expchannel_t channel); static void option_cb(EXTDriver *extp, expchannel_t channel); @@ -69,6 +73,8 @@ typedef enum { } dv_mode; static char current_mode = MODE_SERIAL; +#define REFRESH_RATE 50 // in ms + static void print_mcu_info(void) { uint32_t sdid = SIM->SDID; const char *famid[] = { @@ -113,6 +119,24 @@ static void print_mcu_info(void) { pins[(sdid >> 0) & 15]); } +static void led_cb(void *arg) { + (void) arg; + + palTogglePad(GPIOA, 6); + chSysLockFromISR(); + chVTSetI(&led_vt, MS2ST(500), led_cb, NULL); + chSysUnlockFromISR(); +} + +static void refresh_cb(void *arg) { + (void) arg; + + chSysLockFromISR(); + chVTSetI(&refresh_vt, MS2ST(REFRESH_RATE), refresh_cb, NULL); + chEvtBroadcastI(&refresh_event); + chSysUnlockFromISR(); +} + static void mode_cb(EXTDriver *extp, expchannel_t channel) { (void)extp; (void)channel; @@ -129,45 +153,29 @@ static void adc_celcius_handler(eventid_t id) { chprintf(stream, "celcius: %d\n\r", analogReadTemperature()); } -static void update_handler(eventid_t id) { +static void refresh_handler(eventid_t id) { (void) id; + switch(current_mode) { + case MODE_SERIAL: + updateSerialScreen(); + break; + default: + break; + } } -void init_update_events(void) { - chEvtObjectInit(&ta_update_event); - evtTableHook(orchard_app_events, ta_update_event, update_handler); +static void serial_handler(eventid_t id) { + (void) id; + dvDoSerial(); } -static thread_t *blink_tp = NULL; -static THD_WORKING_AREA(waEvHandlerThread, 96); +static thread_t *evHandler_tp = NULL; +static THD_WORKING_AREA(waEvHandlerThread, 0x500); static THD_FUNCTION(evHandlerThread, arg) { (void)arg; - chRegSetThreadName("Event dispatcher"); - while(true) { - chEvtDispatch(evtHandlers(orchard_app_events), chEvtWaitOne(ALL_EVENTS)); - } -} - -/* - * Application entry point. - */ -int main(void) -{ - /* - * System initializations. - * - HAL initialization, this also initializes the configured device drivers - * and performs the board-specific initializations. - * - Kernel initialization, the main() function becomes a thread and the - * RTOS is active. - */ - halInit(); - chSysInit(); - - // set this low here in case something crashes later on, at least we have the LED on to indicate power-on - palWritePad(GPIOA, 6, PAL_LOW); // mcu_led adcStart(&ADCD1, &adccfg1); analogStart(); @@ -181,26 +189,13 @@ int main(void) print_mcu_info(); chprintf(stream, "free memory at boot: %d bytes\r\n", chCoreGetStatusX()); - orchardGfxInit(); - oledOrchardBanner(); - - // orchardShellRestart(); - evtTableInit(orchard_app_events, 9); - init_update_events(); - - chEvtObjectInit(&adc_celcius_event); - evtTableHook(orchard_app_events, adc_celcius_event, adc_celcius_handler); - - // chEvtObjectInit(&accel_event); - // evtTableHook(orchard_app_events, accel_event, accel_irq); - // accelStart(i2cDriver); + chEvtObjectInit(&refresh_event); + evtTableHook(orchard_app_events, refresh_event, refresh_handler); - // chEvtObjectInit(&accel_test_event); - // evtTableHook(orchard_app_events, accel_test_event, accel_test); - - // evtTableHook(orchard_app_events, accel_pulse, accel_pulse_handler); + chEvtObjectInit(&serial_event); + evtTableHook(orchard_app_events, serial_event, serial_handler); extStart(&EXTD1, &ext_config); // enables interrupts on gpios @@ -209,27 +204,48 @@ int main(void) // palWritePad(GPIOB, 13,PAL_HIGH); // oled_dc // palWritePad(GPIOB, 11,PAL_HIGH); // oled_res + orchardGfxInit(); + oledOrchardBanner(); + + chprintf(stream, "free memory after gfx init: %d bytes\r\n", chCoreGetStatusX()); - blink_tp = chThdCreateStatic(waEvHandlerThread, sizeof(waEvHandlerThread), NORMALPRIO - 20, evHandlerThread, NULL); + // start refreshing the screen + chVTObjectInit(&refresh_vt); + chVTSet(&refresh_vt, MS2ST(REFRESH_RATE), refresh_cb, NULL); - chprintf(stream, "free memory into main loop: %d bytes\r\n", chCoreGetStatusX()); + serial_init = 1; dvInit(); + while(true) { + chEvtDispatch(evtHandlers(orchard_app_events), chEvtWaitOne(ALL_EVENTS)); + } +} + +/* + * Application entry point. + */ +int main(void) +{ + /* + * System initializations. + * - HAL initialization, this also initializes the configured device drivers + * and performs the board-specific initializations. + * - Kernel initialization, the main() function becomes a thread and the + * RTOS is active. + */ + halInit(); + chSysInit(); + + // set this low here in case something crashes later on, at least we have the LED on to indicate power-on + palWritePad(GPIOA, 6, PAL_LOW); // mcu_led + + chVTObjectInit(&led_vt); + chVTSet(&led_vt, MS2ST(500), led_cb, NULL); + + evHandler_tp = chThdCreateStatic(waEvHandlerThread, sizeof(waEvHandlerThread), NORMALPRIO + 10, evHandlerThread, NULL); + while (TRUE) { - switch(current_mode) { - case MODE_SERIAL: - dvDoSerial(); - break; - - default: - break; - } - - // blink LED, without using a sleep function - if( (ST2MS(chVTGetSystemTimeX()) & 0x3FF) < 0x200 ) - palWritePad(GPIOA, 6, PAL_LOW); - else - palWritePad(GPIOA, 6, PAL_HIGH); + // this is now an idle loop } } diff --git a/orchard/orchard-events.h b/orchard/orchard-events.h index 27ac74055..f5a6bf480 100644 --- a/orchard/orchard-events.h +++ b/orchard/orchard-events.h @@ -24,12 +24,8 @@ } */ -extern event_source_t accel_event; -extern event_source_t accel_test_event; -extern event_source_t ta_update_event; -extern event_source_t adc_celcius_event; -extern event_source_t adc_mic_event; - +extern event_source_t serial_event; +extern event_source_t refresh_event; struct ui_info { char *str; diff --git a/os/hal/ports/KINETIS/KL02x/serial_lld.c b/os/hal/ports/KINETIS/KL02x/serial_lld.c index cf026195e..e862ba101 100644 --- a/os/hal/ports/KINETIS/KL02x/serial_lld.c +++ b/os/hal/ports/KINETIS/KL02x/serial_lld.c @@ -76,6 +76,8 @@ static const SerialConfig default_config = { * @param[in] u pointer to an UART I/O block * @param[in] sdp communication channel associated to the UART */ +extern event_source_t serial_event; +extern uint8_t serial_init; static void serve_interrupt(SerialDriver *sdp) { UARTLP_TypeDef *u = sdp->uart; @@ -85,6 +87,10 @@ static void serve_interrupt(SerialDriver *sdp) { chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); if (iqPutI(&sdp->iqueue, u->D) < Q_OK) chnAddFlagsI(sdp, SD_OVERRUN_ERROR); + + if(serial_init) + chEvtBroadcastI(&serial_event); // instrument the serial handler to call our event loop + osalSysUnlockFromISR(); } diff --git a/os/hal/src/serial.c b/os/hal/src/serial.c index 4b5ecf6e7..37fe788ad 100644 --- a/os/hal/src/serial.c +++ b/os/hal/src/serial.c @@ -131,7 +131,7 @@ void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify) { osalEventObjectInit(&sdp->event); sdp->state = SD_STOP; iqObjectInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, inotify, sdp); - oqObjectInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify, sdp); + oqObjectInit(&sdp->oqueue, sdp->ob, 8, onotify, sdp); // rarely tx, so fix at a small level to save space } /**