Files
TI_C2000_F28377S_FreeRTOS/freertos_driverlib_f28377s/main.c
T
2026-09-05 14:12:10 -07:00

464 lines
15 KiB
C

// Standard includes
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <file.h>
#include <limits.h>
#include <string.h>
// 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);
}