/* ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 2011,2012 Giovanni Di Sirio. This file is part of ChibiOS/RT. ChibiOS/RT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS/RT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "ch.h" #include "hal.h" /*===========================================================================*/ /* Configurable settings. */ /*===========================================================================*/ #ifndef RANDOMIZE #define RANDOMIZE FALSE #endif #ifndef ITERATIONS #define ITERATIONS 100 #endif #ifndef NUM_THREADS #define NUM_THREADS 4 #endif #ifndef MAILBOX_SIZE #define MAILBOX_SIZE 4 #endif /*===========================================================================*/ /* Test related code. */ /*===========================================================================*/ #define MSG_SEND_LEFT 0 #define MSG_SEND_RIGHT 1 static bool_t saturated; /* * Mailboxes and buffers. */ static Mailbox mb[NUM_THREADS]; static msg_t b[NUM_THREADS][MAILBOX_SIZE]; /* * Test worker threads. */ static WORKING_AREA(waWorkerThread[NUM_THREADS], 128); static msg_t WorkerThread(void *arg) { static volatile unsigned x = 0; static unsigned cnt = 0; unsigned me = (unsigned)arg; unsigned target; unsigned r; msg_t msg; chRegSetThreadName("worker"); /* Work loop.*/ while (TRUE) { /* Waiting for a message.*/ chMBFetch(&mb[me], &msg, TIME_INFINITE); #if RANDOMIZE /* Pseudo-random delay.*/ { chSysLock(); r = rand() & 15; chSysUnlock(); while (r--) x++; } #else /* Fixed delay.*/ { r = me >> 4; while (r--) x++; } #endif /* Deciding in which direction to re-send the message.*/ if (msg == MSG_SEND_LEFT) target = me - 1; else target = me + 1; if (target < NUM_THREADS) { /* If this thread is not at the end of a chain re-sending the message, note this check works because the variable target is unsigned.*/ msg = chMBPost(&mb[target], msg, TIME_IMMEDIATE); if (msg != RDY_OK) saturated = TRUE; } else { /* Provides a visual feedback about the system.*/ if (++cnt >= 500) { cnt = 0; palTogglePad(GPIOE, GPIOE_LED10_RED); } } } } /* * GPT2 callback. */ static void gpt2cb(GPTDriver *gptp) { msg_t msg; (void)gptp; chSysLockFromIsr(); msg = chMBPostI(&mb[0], MSG_SEND_RIGHT); if (msg != RDY_OK) saturated = TRUE; chSysUnlockFromIsr(); } /* * GPT3 callback. */ static void gpt3cb(GPTDriver *gptp) { msg_t msg; (void)gptp; chSysLockFromIsr(); msg = chMBPostI(&mb[NUM_THREADS - 1], MSG_SEND_LEFT); if (msg != RDY_OK) saturated = TRUE; chSysUnlockFromIsr(); } /* * GPT2 configuration. */ static const GPTConfig gpt2cfg = { 1000000, /* 1MHz timer clock.*/ gpt2cb /* Timer callback.*/ }; /* * GPT3 configuration. */ static const GPTConfig gpt3cfg = { 1000000, /* 1MHz timer clock.*/ gpt3cb /* Timer callback.*/ }; /*===========================================================================*/ /* Generic demo code. */ /*===========================================================================*/ static void print(char *p) { while (*p) { chSequentialStreamPut(&SD1, *p++); } } static void println(char *p) { while (*p) { chSequentialStreamPut(&SD1, *p++); } chSequentialStreamWrite(&SD1, (uint8_t *)"\r\n", 2); } static void printn(uint32_t n) { char buf[16], *p; if (!n) chSequentialStreamPut(&SD1, '0'); else { p = buf; while (n) *p++ = (n % 10) + '0', n /= 10; while (p > buf) chSequentialStreamPut(&SD1, *--p); } } /* * Application entry point. */ int main(void) { unsigned i; gptcnt_t interval, threshold, worst; /* * 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(); /* * Activates the serial driver 1, PA9 and PA10 are routed to USART1. */ sdStart(&SD1, NULL); palSetPadMode(GPIOA, 9, PAL_MODE_ALTERNATE(7)); /* USART1 TX. */ palSetPadMode(GPIOA, 10, PAL_MODE_ALTERNATE(7)); /* USART1 RX. */ /* * Activates GPTs. */ gptStart(&GPTD2, &gpt2cfg); gptStart(&GPTD3, &gpt3cfg); /* * Initializes the mailboxes and creates the worker threads. */ for (i = 0; i < NUM_THREADS; i++) { chMBInit(&mb[i], b[i], MAILBOX_SIZE); chThdCreateStatic(waWorkerThread[i], sizeof waWorkerThread[i], NORMALPRIO - 20, WorkerThread, (void *)i); } /* * Test procedure. */ println(""); println("*** ChibiOS/RT IRQ-STORM long duration test"); println("***"); print("*** Kernel: "); println(CH_KERNEL_VERSION); print("*** Compiled: "); println(__DATE__ " - " __TIME__); #ifdef CH_COMPILER_NAME print("*** Compiler: "); println(CH_COMPILER_NAME); #endif print("*** Architecture: "); println(CH_ARCHITECTURE_NAME); #ifdef CH_CORE_VARIANT_NAME print("*** Core Variant: "); println(CH_CORE_VARIANT_NAME); #endif #ifdef CH_PORT_INFO print("*** Port Info: "); println(CH_PORT_INFO); #endif #ifdef PLATFORM_NAME print("*** Platform: "); println(PLATFORM_NAME); #endif #ifdef BOARD_NAME print("*** Test Board: "); println(BOARD_NAME); #endif println("***"); print("*** System Clock: "); printn(STM32_SYSCLK); println(""); print("*** Iterations: "); printn(ITERATIONS); println(""); print("*** Randomize: "); printn(RANDOMIZE); println(""); print("*** Threads: "); printn(NUM_THREADS); println(""); print("*** Mailbox size: "); printn(MAILBOX_SIZE); println(""); println(""); worst = 0; for (i = 1; i <= ITERATIONS; i++){ print("Iteration "); printn(i); println(""); saturated = FALSE; threshold = 0; for (interval = 2000; interval >= 10; interval -= interval / 10) { gptStartContinuous(&GPTD2, interval - 1); /* Slightly out of phase.*/ gptStartContinuous(&GPTD3, interval + 1); /* Slightly out of phase.*/ chThdSleepMilliseconds(1000); gptStopTimer(&GPTD2); gptStopTimer(&GPTD3); if (!saturated) print("."); else { print("#"); if (threshold == 0) threshold = interval; } } /* Gives the worker threads a chance to empty the mailboxes before next cycle.*/ chThdSleepMilliseconds(20); println(""); print("Saturated at "); printn(threshold); println(" uS"); println(""); if (threshold > worst) worst = threshold; } gptStopTimer(&GPTD2); gptStopTimer(&GPTD3); print("Worst case at "); printn(worst); println(" uS"); println(""); println("Test Complete"); /* * Normal main() thread activity, nothing in this test. */ while (TRUE) { chThdSleepMilliseconds(5000); } }