/// @file /// @brief QUTEST port for the EK-TM4C123GXL board /// @ingroup qs /// @cond ///*************************************************************************** /// Last updated for version 6.3.8 /// Last updated on 2019-01-24 /// /// Q u a n t u m L e a P s /// ------------------------ /// Modern Embedded Software /// /// Copyright (C) 2005-2019 Quantum Leaps, LLC. All rights reserved. /// /// This program is open source 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. /// /// Alternatively, this program may be distributed and modified under the /// terms of Quantum Leaps commercial licenses, which expressly supersede /// the GNU General Public License and are specifically designed for /// licensees interested in retaining the proprietary status of their code. /// /// This program 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 . /// /// Contact information: /// https://state-machine.com /// mailto:info@state-machine.com ///*************************************************************************** /// @endcond #include "qpcpp.h" #include "TM4C123GH6PM.h" // the device specific header (TI) #include "rom.h" // the built-in ROM functions (TI) #include "sysctl.h" // system control driver (TI) #include "gpio.h" // GPIO driver (TI) // add other drivers if necessary... //Q_DEFINE_THIS_MODULE("qutest_port") using namespace QP; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! CAUTION !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Assign a priority to EVERY ISR explicitly by calling NVIC_SetPriority(). // DO NOT LEAVE THE ISR PRIORITIES AT THE DEFAULT VALUE! // enum KernelUnawareISRs { // see NOTE00 UART0_PRIO, // ... MAX_KERNEL_UNAWARE_CMSIS_PRI // keep always last }; // "kernel-unaware" interrupts can't overlap "kernel-aware" interrupts //Q_ASSERT_COMPILE(MAX_KERNEL_UNAWARE_CMSIS_PRI <= QF_AWARE_ISR_CMSIS_PRI); // ISRs defined in this BSP -------------------------------------------------- extern "C" void UART0_IRQHandler(void); // prototype // Local-scope objects ------------------------------------------------------- #define LED_RED (1U << 1) #define LED_BLUE (1U << 2) #define LED_GREEN (1U << 3) #define BTN_SW1 (1U << 4) #define BTN_SW2 (1U << 0) #define UART_BAUD_RATE 115200U #define UART_FR_TXFE (1U << 7) #define UART_FR_RXFE (1U << 4) #define UART_TXFIFO_DEPTH 16U //............................................................................ extern "C" { // ISR for receiving bytes from the QSPY Back-End // NOTE: This ISR is "QF-unaware" meaning that it does not interact with // the QF/QK and is not disabled. Such ISRs don't need to call QK_ISR_ENTRY/ // QK_ISR_EXIT and they cannot post or publish events. // void UART0_IRQHandler(void) { // while RX FIFO NOT empty while ((UART0->FR & UART_FR_RXFE) == 0) { uint32_t b = UART0->DR; QP::QS::rxPut(b); } } } // extern "C" // QS callbacks ============================================================== bool QS::onStartup(void const *arg) { static uint8_t qsTxBuf[2*1024]; // buffer for QS transmit channel static uint8_t qsRxBuf[100]; // buffer for QS receive channel uint32_t tmp; initBuf (qsTxBuf, sizeof(qsTxBuf)); rxInitBuf(qsRxBuf, sizeof(qsRxBuf)); // NOTE: SystemInit() already called from the startup code // but SystemCoreClock needs to be updated // SystemCoreClockUpdate(); // configure the FPU usage by choosing one of the options... */ #if 0 // OPTION 1: // Use the automatic FPU state preservation and the FPU lazy stacking. // // NOTE: // Use the following setting when FPU is used in more than one task or // in any ISRs. This setting is the safest and recommended, but requires // extra stack space and CPU cycles. // FPU->FPCCR |= (1U << FPU_FPCCR_ASPEN_Pos) | (1U << FPU_FPCCR_LSPEN_Pos); #else // OPTION 2: // Do NOT to use the automatic FPU state preservation and // do NOT to use the FPU lazy stacking. // // NOTE: // Use the following setting when FPU is used in ONE task only and not // in any ISR. This setting is very efficient, but if more than one task // (or ISR) start using the FPU, this can lead to corruption of the // FPU registers. This option should be used with CAUTION. // FPU->FPCCR &= ~((1U << FPU_FPCCR_ASPEN_Pos) | (1U << FPU_FPCCR_LSPEN_Pos)); #endif // FPU // enable clock for to the peripherals used by this application... SYSCTL->RCGCGPIO |= (1U << 5); // enable Run mode for GPIOF // configure the LEDs and push buttons GPIOF->DIR |= (LED_RED | LED_GREEN | LED_BLUE);// set direction: output GPIOF->DEN |= (LED_RED | LED_GREEN | LED_BLUE); // digital enable GPIOF->DATA_Bits[LED_RED] = 0U; // turn the LED off GPIOF->DATA_Bits[LED_GREEN] = 0U; // turn the LED off GPIOF->DATA_Bits[LED_BLUE] = 0U; // turn the LED off // configure the Buttons GPIOF->DIR &= ~(BTN_SW1 | BTN_SW2); // set direction: input ROM_GPIOPadConfigSet(GPIOF_BASE, (BTN_SW1 | BTN_SW2), GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU); // enable clock for UART0 and GPIOA (used by UART0 pins) SYSCTL->RCGCUART |= (1U << 0); // enable Run mode for UART0 SYSCTL->RCGCGPIO |= (1U << 0); // enable Run mode for GPIOA // configure UART0 pins for UART operation tmp = (1U << 0) | (1U << 1); GPIOA->DIR &= ~tmp; GPIOA->SLR &= ~tmp; GPIOA->ODR &= ~tmp; GPIOA->PUR &= ~tmp; GPIOA->PDR &= ~tmp; GPIOA->AMSEL &= ~tmp; // disable analog function on the pins GPIOA->AFSEL |= tmp; // enable ALT function on the pins GPIOA->DEN |= tmp; // enable digital I/O on the pins GPIOA->PCTL &= ~0x00U; GPIOA->PCTL |= 0x11U; // configure the UART for the desired baud rate, 8-N-1 operation tmp = (((SystemCoreClock * 8U) / UART_BAUD_RATE) + 1U) / 2U; UART0->IBRD = tmp / 64U; UART0->FBRD = tmp % 64U; UART0->LCRH = (0x3U << 5); // configure 8-N-1 operation UART0->LCRH |= (0x1U << 4); // enable FIFOs UART0->CTL = (1U << 0) // UART enable | (1U << 8) // UART TX enable | (1U << 9); // UART RX enable // configure UART interrupts (for the RX channel) UART0->IM |= (1U << 4) | (1U << 6); // enable RX and RX-TO interrupt UART0->IFLS |= (0x2U << 2); // interrupt on RX FIFO half-full // enable the UART RX interrupt... NVIC_SetPriorityGrouping(0U); NVIC_SetPriority(UART0_IRQn, UART0_PRIO); NVIC_EnableIRQ(UART0_IRQn); // UART0 interrupt used for QS-RX return true; // return success } //............................................................................ void QS::onCleanup(void) { } //............................................................................ void QS::onFlush(void) { uint16_t fifo = UART_TXFIFO_DEPTH; // Tx FIFO depth uint8_t const *block; while ((block = getBlock(&fifo)) != (uint8_t *)0) { GPIOF->DATA_Bits[LED_GREEN] = LED_GREEN; // busy-wait as long as TX FIFO has data to transmit while ((UART0->FR & UART_FR_TXFE) == 0) { } while (fifo-- != 0) { // any bytes in the block? UART0->DR = *block++; // put into the TX FIFO } fifo = UART_TXFIFO_DEPTH; // re-load the Tx FIFO depth GPIOF->DATA_Bits[LED_GREEN] = 0U; } } //............................................................................ // callback function to reset the target (to be implemented in the BSP) void QS::onReset(void) { NVIC_SystemReset(); } //............................................................................ void QS::onTestLoop() { rxPriv_.inTestLoop = true; while (rxPriv_.inTestLoop) { // turn the LED1 on and off (glow) GPIOF->DATA_Bits[LED_BLUE] = LED_BLUE; // turn the Blue LED on GPIOF->DATA_Bits[LED_BLUE] = 0U; // turn the Blue LED off rxParse(); // parse all the received bytes if ((UART0->FR & UART_FR_TXFE) != 0U) { // TX done? uint16_t fifo = UART_TXFIFO_DEPTH; // max bytes we can accept uint8_t const *block; block = getBlock(&fifo); // try to get next block to transmit while (fifo-- != 0) { // any bytes in the block? UART0->DR = *block++; // put into the FIFO } } } // set inTestLoop to true in case calls to QS_onTestLoop() nest, // which can happen through the calls to QS_TEST_PAUSE(). rxPriv_.inTestLoop = true; }