// Standard includes #include #include #include #include #include #include // Driverlib headers #include "driverlib.h" #include "device.h" #include "sci.h" // Customized headers #include "uart_drv.h" #include "at24cm02.h" #include "sine_table.h" // FreeRTOS headers #include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include "queue.h" #include "timers.h" #if defined (__TI_EABI__) void* malloc(size_t xSize) { (void) xSize; taskDISABLE_INTERRUPTS(); for (;;) { ESTOP0; } } #pragma WEAK (malloc) #endif #if(configAPPLICATION_ALLOCATED_HEAP == 1) uint8_t ucHeap[configTOTAL_HEAP_SIZE]; #pragma DATA_SECTION(ucHeap, ".freertosHeap") #pragma DATA_ALIGN(ucHeap, portBYTE_ALIGNMENT) #endif // -------------------------------------------------------------------- #define LED_R 41U // Red LED #define LED_B 58U // Blue LED #define SCI_RXDA_PIN 85U #define SCI_TXDA_PIN 84U #define EPWM6A_GPIO 10U #define EPWM6A_FREQUENCY_HZ 50000UL // 50KHz #define EPWM6A_DUTY_PERCENT 75U // 75% #define EPWM_CLOCK_HZ (DEVICE_SYSCLK_FREQ / 2UL) #define EPWM6A_PERIOD_COUNTS (EPWM_CLOCK_HZ / EPWM6A_FREQUENCY_HZ) #define EPWM6A_PERIOD_TICKS (EPWM6A_PERIOD_COUNTS - 1UL) #define EPWM6A_COMPARE_TICKS ((EPWM6A_PERIOD_COUNTS * EPWM6A_DUTY_PERCENT) / 100UL) #define DAC_SINE_FREQUENCY_HZ 1000UL #define DAC_SAMPLE_FREQUENCY_HZ (DAC_SINE_FREQUENCY_HZ * SINE_TABLE_LENGTH) #define DAC_SAMPLE_PERIOD_TICKS ((EPWM_CLOCK_HZ / DAC_SAMPLE_FREQUENCY_HZ) - 1UL) // UART: SCIA void UartSetup(void); void UartPutChar(uint16_t charToWrite); // CPU Timer 1 void configCPUTimer(uint32_t cpuTimer, uint32_t period_us); __interrupt void timer1_ISR(void); // ePWM6A: GPIO10, 50KHz, 75% duty cycle void initEPWM6A(void); // DACOUTB sine output and ePWM7 supplies the sample interrupt void initDACBSine(void); __interrupt void dacUpdateISR(void); static volatile uint16_t sineTableIndex = 0U; // EEPROM: AT24CM02 (2Mbit) static EEPROM_Status eepromInitStatus = EEPROM_STATUS_NOT_INITIALIZED; static uint16_t eepromReadData[AT24CM02_PAGE_SIZE_BYTES]; static uint16_t eepromWriteData[AT24CM02_PAGE_SIZE_BYTES]; // FreeRTOS const char * volatile g_overflow_task_name = NULL; TaskHandle_t volatile g_overflow_task_handle = NULL; void RedLED_Task(void *pvParameters); void BlueLED_Task(void *pvParameters); void EEPROM_Task(void *pvParameters); static SemaphoreHandle_t xSemaphore = NULL; void main(void) { // Initializes device clock and peripherals Device_init(); // Initializes PIE and clears PIE registers. Disables CPU interrupts Interrupt_initModule(); // --------------------------- Initializes GPIO --------------------------- Device_initGPIO(); GPIO_setPadConfig(LED_R, GPIO_PIN_TYPE_STD); GPIO_setDirectionMode(LED_R, GPIO_DIR_MODE_OUT); GPIO_writePin(LED_R, 0); GPIO_setPadConfig(LED_B, GPIO_PIN_TYPE_STD); GPIO_setDirectionMode(LED_B, GPIO_DIR_MODE_OUT); GPIO_writePin(LED_B, 0); // ------------------------------------------------------------------------ // Clear all interrupts and initialize PIE vector table // Disable CPU interrupts DINT; // Disable CPU interrupts and clear all CPU interrupt flags IER = 0x0000; IFR = 0x0000; // Initializes the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR) Interrupt_initVectorTable(); // ------------------------- Configure CPU Timer -------------------------- // ISR functions found within this project Interrupt_register(INT_TIMER1, &timer1_ISR); // Configure CPU timer 1 to interrupt every given period: 1000000 us configCPUTimer(CPUTIMER1_BASE, 1000000); CPUTimer_clearOverflowFlag(CPUTIMER1_BASE); // Enable CPU timer 1 interrupt and start CPU timer 1 Interrupt_enable(INT_TIMER1); CPUTimer_startTimer(CPUTIMER1_BASE); // ------------------------------------------------------------------------ // Enable global Interrupts and higher priority real-time debug events EINT; // Enable Global interrupt INTM ERTM; // Enable Global real-time interrupt DBGM // ------------------------------------------------------------------------ // SCIA: GPIO84/GPIO85 // Add the UART device. When fopen is called with a filename that // begins "uart:", the UART device will be used to handle the file add_device("uart", _SSA, UART_open, UART_close, UART_read, UART_write, UART_lseek, UART_unlink, UART_rename); // Assign stdout to be a UART device assert(freopen("uart:", "w", stdout) != NULL); // GPIO91/GPIO92 and I2CA are configured by the EEPROM driver eepromInitStatus = EEPROM_init(); // GPIO10 outputs ePWM6A at 50KHz with a 75% duty cycle initEPWM6A(); // Generate a 1 kHz sine wave on DACOUTB initDACBSine(); // ------------------------------- FreeRTOS ------------------------------- xSemaphore = xSemaphoreCreateBinary(); // 1 stack element = 1 * uint16_t = 16 bits = 2 conventional bytes // 256 stack elements * 2 bytes = 512 conventional bytes xTaskCreate(RedLED_Task, (const char*) "RedLED_Task", 256, NULL, 1, NULL); xTaskCreate(BlueLED_Task, (const char*) "BlueLED_Task", 256, NULL, 1, NULL); xTaskCreate(EEPROM_Task, (const char*) "EEPROM_Task", 384, NULL, 2, NULL); // Start the scheduler. This should not return vTaskStartScheduler(); } void RedLED_Task(void *pvParameters) { (void)pvParameters; int uart_count = 0; UBaseType_t uxRemainingWords; while (1) { if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) { GPIO_togglePin(LED_R); uart_count++; printf("FreeRTOS running on the F28377S Coreboard V1.3, %d!\r\n", uart_count); uxRemainingWords = uxTaskGetStackHighWaterMark(NULL); printf("RedLED_Task unused stack: %d stack elements (%d bytes)\r\n", (int)uxRemainingWords, (int)(uxRemainingWords * sizeof(StackType_t) * (CHAR_BIT / 8U))); } } } void BlueLED_Task(void *pvParameters) { (void)pvParameters; while (1) { GPIO_togglePin(LED_B); vTaskDelay(pdMS_TO_TICKS(500)); } } void EEPROM_Task(void *pvParameters) { uint16_t i; uint16_t mismatchCount = 0U; EEPROM_Status status = eepromInitStatus; const char *operation = "initialization"; (void)pvParameters; // Allow the EEPROM supply and power-on reset to settle before the first // command. The datasheet requires at least 100 us after VCC is stable. vTaskDelay(pdMS_TO_TICKS(2U)); for (i = 0U; i < AT24CM02_PAGE_SIZE_BYTES; i++) { eepromWriteData[i] = i; eepromReadData[i] = 0U; } if (status == EEPROM_STATUS_SUCCESS) { operation = "page write"; status = EEPROM_writePage(eepromWriteData, AT24CM02_DEFAULT_ADDRESS, AT24CM02_PAGE_COUNT, AT24CM02_PAGE_SIZE_BYTES, pdMS_TO_TICKS(50U)); } if (status == EEPROM_STATUS_SUCCESS) { operation = "page read"; status = EEPROM_readPage(eepromReadData, AT24CM02_DEFAULT_ADDRESS, AT24CM02_PAGE_COUNT, AT24CM02_PAGE_SIZE_BYTES, pdMS_TO_TICKS(50U)); } if (status == EEPROM_STATUS_SUCCESS) { for (i = 0U; i < AT24CM02_PAGE_SIZE_BYTES; i++) { if (eepromReadData[i] != eepromWriteData[i]) { mismatchCount++; } } printf("AT24CM02 page %u test: %s (%u mismatches)\r\n", AT24CM02_PAGE_COUNT, (mismatchCount == 0U) ? "PASS" : "FAIL", mismatchCount); } else { printf("AT24CM02 %s failed: %s\r\n", operation, EEPROM_statusString(status)); } vTaskDelete(NULL); } void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) { g_overflow_task_handle = xTask; g_overflow_task_name = pcTaskName; // points to the task name string taskDISABLE_INTERRUPTS(); for (;;) { __asm(" NOP"); // set breakpoint here and inspect g_overflow_task_name } } void vApplicationMallocFailedHook(void) { taskDISABLE_INTERRUPTS(); for(;;){} } // ----------------------------------------------------------------------------------------- void initEPWM6A(void) { // Route ePWM6A to GPIO10 GPIO_setMasterCore(EPWM6A_GPIO, GPIO_CORE_CPU1); GPIO_setPadConfig(EPWM6A_GPIO, GPIO_PIN_TYPE_STD); GPIO_setPinConfig(GPIO_10_EPWM6A); // The F28377S runs at 200 MHz. Divide EPWMCLK by two so TBCLK is // 100 MHz, then freeze all ePWM time-base clocks during configuration SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_2); SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC); EPWM_setClockPrescaler(EPWM6_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1); EPWM_setTimeBaseCounterMode(EPWM6_BASE, EPWM_COUNTER_MODE_UP); EPWM_setTimeBasePeriod(EPWM6_BASE, (uint16_t)EPWM6A_PERIOD_TICKS); EPWM_setTimeBaseCounter(EPWM6_BASE, 0U); EPWM_disablePhaseShiftLoad(EPWM6_BASE); EPWM_setPhaseShift(EPWM6_BASE, 0U); EPWM_setCounterCompareValue(EPWM6_BASE, EPWM_COUNTER_COMPARE_A, (uint16_t)EPWM6A_COMPARE_TICKS); EPWM_setCounterCompareShadowLoadMode(EPWM6_BASE, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO); // Drive ePWM6A high at the start of each period and low at CMPA EPWM_setActionQualifierAction(EPWM6_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); EPWM_setActionQualifierAction(EPWM6_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA); SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC); } // ----------------------------------------------------------------------------------------- void initDACBSine(void) { // Configure DACOUTB for 12-bit output referenced to ADC VREFHI. DAC_setReferenceVoltage(DACB_BASE, DAC_REF_ADC_VREFHI); DAC_setLoadMode(DACB_BASE, DAC_LOAD_SYSCLK); DAC_setShadowValue(DACB_BASE, sineTable[0U]); DAC_enableOutput(DACB_BASE); DEVICE_DELAY_US(10U); // Use ePWM7 only as a 100 kHz sample clock. With a 100 MHz TBCLK, // up-count mode and TBPRD = 999 produce one interrupt every 10 us. SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC); SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_2); EPWM_setClockPrescaler(EPWM7_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1); EPWM_setTimeBaseCounterMode(EPWM7_BASE, EPWM_COUNTER_MODE_UP); EPWM_setTimeBasePeriod(EPWM7_BASE, (uint16_t)DAC_SAMPLE_PERIOD_TICKS); EPWM_setTimeBaseCounter(EPWM7_BASE, 0U); EPWM_disablePhaseShiftLoad(EPWM7_BASE); EPWM_setPhaseShift(EPWM7_BASE, 0U); EPWM_setInterruptSource(EPWM7_BASE, EPWM_INT_TBCTR_ZERO); EPWM_setInterruptEventCount(EPWM7_BASE, 1U); EPWM_clearEventTriggerInterruptFlag(EPWM7_BASE); Interrupt_register(INT_EPWM7, &dacUpdateISR); Interrupt_enable(INT_EPWM7); EPWM_enableInterrupt(EPWM7_BASE); sineTableIndex = 1U; SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC); } __interrupt void dacUpdateISR(void) { DAC_setShadowValue(DACB_BASE, sineTable[sineTableIndex]); sineTableIndex++; if (sineTableIndex >= SINE_TABLE_LENGTH) { sineTableIndex = 0U; } EPWM_clearEventTriggerInterruptFlag(EPWM7_BASE); Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3); } // ----------------------------------------------------------------------------------------- // This function initializes the selected timer to the period specified // by the "freq" and "period" variables. The "freq" is CPU frequency // in Hz and the period in us. void configCPUTimer(uint32_t cpuTimer, uint32_t period_us) { uint32_t periodCount, freq = DEVICE_SYSCLK_FREQ; // Initialize timer period periodCount = ((freq / 1000000) * period_us); CPUTimer_setPeriod(cpuTimer, periodCount); // Set pre-scale counter to divide by 1 (SYSCLKOUT) CPUTimer_setPreScaler(cpuTimer, 0); // Initializes timer control register CPUTimer_stopTimer(cpuTimer); CPUTimer_reloadTimerCounter(cpuTimer); CPUTimer_setEmulationMode(cpuTimer, CPUTIMER_EMULATIONMODE_STOPAFTERNEXTDECREMENT); CPUTimer_enableInterrupt(cpuTimer); } // Timer 1 ISR function __interrupt void timer1_ISR(void) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; if (xSemaphore != NULL) { xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } CPUTimer_clearOverflowFlag(CPUTIMER1_BASE); } // ----------------------------------------------------------------------------------------- // Configures SCIA, baud rate is 115200 void UartSetup(void) { // SCIA RX: GPIO85 GPIO_setMasterCore(SCI_RXDA_PIN, GPIO_CORE_CPU1); GPIO_setPinConfig(GPIO_85_SCIRXDA); GPIO_setDirectionMode(SCI_RXDA_PIN, GPIO_DIR_MODE_IN); GPIO_setPadConfig(SCI_RXDA_PIN, GPIO_PIN_TYPE_STD); GPIO_setQualificationMode(SCI_RXDA_PIN, GPIO_QUAL_ASYNC); // SCIA TX: GPIO84 GPIO_setMasterCore(SCI_TXDA_PIN, GPIO_CORE_CPU1); GPIO_setPinConfig(GPIO_84_SCITXDA); GPIO_setDirectionMode(SCI_TXDA_PIN, GPIO_DIR_MODE_OUT); GPIO_setPadConfig(SCI_TXDA_PIN, GPIO_PIN_TYPE_STD); GPIO_setQualificationMode(SCI_TXDA_PIN, GPIO_QUAL_ASYNC); // Configure SCIA SCI_performSoftwareReset(SCIA_BASE); SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200U, SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE); SCI_resetChannels(SCIA_BASE); SCI_resetRxFIFO(SCIA_BASE); SCI_resetTxFIFO(SCIA_BASE); // Recommended when using FIFO SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_TXFF | SCI_INT_RXFF); SCI_enableFIFO(SCIA_BASE); SCI_enableModule(SCIA_BASE); SCI_performSoftwareReset(SCIA_BASE); } // Implements SCI based putchar() void UartPutChar(uint16_t charToWrite) { SCI_writeCharBlockingFIFO(SCIA_BASE, charToWrite); }