英文缩写
- C28X CPU+FPU(floating-point processor)
- Trigonometric Math Unit (TMU)
- Viterbi, Complex Math and CRC Unit (VCU)
- Cyclic Redundancy Check (CRC)
- start-of-conversion (SOC)
外设或通信协议
- local interconnect network (LIN)
- serial communication interface (SCI)
- Controller Area Network (CAN)
- Fast Serial Interface (FSI)
- inter-integrated circuit (I2C)
- serial peripheral interface (SPI)
- enhanced pulse width modulator (ePWM)
寄存器编程的例程在C:\ti\c2000\C2000Ware_2_01_00_00\device_support\f28004x,
库函数编程的例程在C:\ti\c2000\C2000Ware_2_01_00_00\driverlib\f28004x\examples。
示例工程研究
实验参考的例程库函数版,主要针对ADC和CAN
例程是针对ControlCARD开发的,如果想将其应用到LaunchPad上,自然需要更改引脚映射。具体的代码可以在devices.h中找到。
芯片在上电或复位后会自动使能看门狗,所以初始化函数的第一句是将其关闭。
Register protection is enabled by default at startup. While protected, all writes to protected registers by the CPU
are ignored.
研究三个例子代码
- // FILE: led_ex1_blinky.c
//! This example demonstrates how to blink a LED.
//! If using LaunchPad, select build configuration for LAUNCHXL.
- // FILE: adc_ex1_soc_software.c
//! This example converts some voltages on ADCA and ADCB based on a software
//! trigger.
- // FILE: adc_ex3_temp_sensor.c
//! This example sets up the ePWM to periodically trigger the ADC. The
//! ADC converts the internal connection to the temperature sensor,
//! which is then interpreted as a temperature by calling the
//! ADC_getTemperatureC() function.
- // FILE: can_ex1_loopback.c
//! This example shows the basic setup of CAN in order to transmit and receive
//! messages on the CAN bus. The CAN peripheral is configured to transmit
//! messages with a specific CAN ID. A message is then transmitted once per
//! second, using a simple delay loop for timing. The message that is sent is
//! a 2 byte message that contains an incrementing pattern.
//led_ex1_blinky.c
void main(void)
{
//设备初始化
Device_init();
//设备引脚初始化
Device_initGPIO();
//设备引脚配置
GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD);
GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);
//初始化并清除 PIE registers. 关闭 CPU interrupts.
Interrupt_initModule();
// 初始化 PIE vector table ,指向 the shell Interrupt
Interrupt_initVectorTable();
// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
EINT;
ERTM;
for(;;)
{
// Turn on LED
GPIO_writePin(DEVICE_GPIO_PIN_LED1, 0);
// Delay for a bit.
DEVICE_DELAY_US(500000);
// Turn off LED
GPIO_writePin(DEVICE_GPIO_PIN_LED1, 1);
// Delay for a bit.
DEVICE_DELAY_US(500000);
}
}
FILE: adc_ex1_soc_software.c
void main(void)
{
Device_init();
Device_initGPIO();
Interrupt_initModule();
Interrupt_initVectorTable();
// Set up ADCs, initializing the SOCs to be triggered by software
initADCs();
initADCSOCs();
EINT;
ERTM;
while(1)
{
//
// Convert, wait for completion, and store results
//
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER1);
ADC_forceSOC(ADCB_BASE, ADC_SOC_NUMBER0);
ADC_forceSOC(ADCB_BASE, ADC_SOC_NUMBER1);
//
// Wait for ADCA to complete, then acknowledge flag
//
while(ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1) == false)
{
}
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
//
// Wait for ADCB to complete, then acknowledge flag
//
while(ADC_getInterruptStatus(ADCB_BASE, ADC_INT_NUMBER1) == false)
{
}
ADC_clearInterruptStatus(ADCB_BASE, ADC_INT_NUMBER1);
//
// Store results
//
adcAResult0 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
adcAResult1 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER1);
adcBResult0 = ADC_readResult(ADCBRESULT_BASE, ADC_SOC_NUMBER0);
adcBResult1 = ADC_readResult(ADCBRESULT_BASE, ADC_SOC_NUMBER1);
//
// Software breakpoint. At this point, conversion results are stored in
// adcAResult0, adcAResult1, adcBResult0, and adcBResult1.
//
// Hit run again to get updated conversions.
//
ESTOP0;
}
}
//FILE: adc_ex3_temp_sensor.c
void main(void)
{
Device_init();
Device_initGPIO();
Interrupt_initModule();
Interrupt_initVectorTable();
//
// Interrupts that are used in this example are re-mapped to ISR functions
// found within this file.
//
Interrupt_register(INT_ADCB1, &adcB1ISR);
//
// Set up the ADC and the ePWM and initialize the SOC
//
initADC();
initEPWM();
initADCSOC();
// Enable the temperature sensor and give it 500 us to power up
ASysCtl_enableTemperatureSensor();
DEVICE_DELAY_US(500);
// Enable ADC interrupt
Interrupt_enable(INT_ADCB1);
// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
EINT;
ERTM;
// Start ePWM1, enabling SOCA and putting the counter in up-count mode
EPWM_enableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
while(1)
{
;
}
}
void main(void)
{
uint16_t txMsgData[2], rxMsgData[2];
Device_init();
Device_initGPIO();
GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA);
//
// Initialize the CAN controller
//
CAN_initModule(CANA_BASE);
//
// Set up the CAN bus bit rate to 500kHz
// Refer to the Driver Library User Guide for information on how to set
// tighter timing control. Additionally, consult the device data sheet
// for more information about the CAN module clocking.
//
CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 500000, 20);
Interrupt_initModule();
Interrupt_initVectorTable();
EINT;
ERTM;
//
// Enable CAN test mode with external loopback
//
CAN_enableTestMode(CANA_BASE, CAN_TEST_EXL);
//
// Initialize the transmit message object used for sending CAN messages.
// Message Object Parameters:
// Message Object ID Number: 1
// Message Identifier: 0x1234
// Message Frame: Standard
// Message Type: Transmit
// Message ID Mask: 0x0
// Message Object Flags: None
// Message Data Length: 2 Bytes
//
CAN_setupMessageObject(CANA_BASE, 1, 0x1234, CAN_MSG_FRAME_STD,
CAN_MSG_OBJ_TYPE_TX, 0, CAN_MSG_OBJ_NO_FLAGS,
MSG_DATA_LENGTH);
//
// Initialize the receive message object used for receiving CAN messages.
// Message Object Parameters:
// Message Object ID Number: 2
// Message Identifier: 0x1234
// Message Frame: Standard
// Message Type: Receive
// Message ID Mask: 0x0
// Message Object Flags: None
// Message Data Length: 2 Bytes
//
CAN_setupMessageObject(CANA_BASE, 2, 0x1234, CAN_MSG_FRAME_STD,
CAN_MSG_OBJ_TYPE_RX, 0, CAN_MSG_OBJ_NO_FLAGS,
MSG_DATA_LENGTH);
//
// Start CAN module operations
//
CAN_startModule(CANA_BASE);
//
// Setup send and receive buffers
//
txMsgData[0] = 0x01;
txMsgData[1] = 0x02;
*(uint16_t *)rxMsgData = 0;
//
// Loop Forever - Send and Receive data continuously
//
for(;;)
{
//
// Send CAN message data from message object 1
//
CAN_sendMessage(CANA_BASE, 1, MSG_DATA_LENGTH, txMsgData);
//
// Delay before receiving the data
//
DEVICE_DELAY_US(500000);
//
// Read CAN message object 2 and check for new data
//
if (CAN_readMessage(CANA_BASE, 2, rxMsgData))
{
//
// Check that received data matches sent data.
// Device will halt here during debug if data doesn't match.
//
if((txMsgData[0] != rxMsgData[0]) ||
(txMsgData[1] != rxMsgData[1]))
{
Example_Fail = 1;
asm(" ESTOP0");
}
else
{
//
// Increment message received counter
//
msgCount++;
Example_PassCount++;
}
}
else
{
//
// Device will halt here during debug if no new data was received.
//
Example_Fail = 1;
asm(" ESTOP0");
}
//
// Increment the value in the transmitted message data.
//
txMsgData[0] += 0x01;
txMsgData[1] += 0x01;
//
// Reset data if exceeds a byte
//
if(txMsgData[0] > 0xFF)
{
txMsgData[0] = 0;
}
if(txMsgData[1] > 0xFF)
{
txMsgData[1] = 0;
}
}
}
总结基本共同的步骤
1、 Device_init(); //看门狗时钟
2、Device_initGPIO(); //实际只是解除锁定,没有真正配置
2.1 设置引脚模式
- GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
- GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA);
- GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD);
- GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);
3、外设初始化(可以包括引脚复用)
4、Interrupt_initModule();
5、Interrupt_initVectorTable();
6、// Enable Global Interrupt (INTM) and realtime interrupt (DBGM) //开全局中断
EINT;
ERTM;
7、使能外设
通用函数说明
1、Device_init()函数的说明
// Function to initialize the device. Primarily initializes system control to a
// known state by disabling the watchdog, setting up the SYSCLKOUT frequency,
// and enabling the clocks to the peripherals.
// The function also configures the GPIO pins 22 and 23 in digital mode.
// To configure these pins as analog pins, use the function GPIO_setAnalogMode
2、GPIO引脚说明
在文件 FILE: pin_map.h 定义了每个引脚并用的模式
在device.h里面的引脚宏定义都是来自 pin_map.h,往下就是寄存器地址了,寄存器编程。
以CAN协议为例
//from device.h
// CAN External Loopback
//
#define DEVICE_GPIO_CFG_CANRXA GPIO_30_CANA_RX // "pinConfig" for CANA RX
#define DEVICE_GPIO_CFG_CANTXA GPIO_31_CANA_TX // "pinConfig" for CANA TX
#define DEVICE_GPIO_CFG_CANRXB GPIO_10_CANB_RX // "pinConfig" for CANB RX
#define DEVICE_GPIO_CFG_CANTXB GPIO_8_CANB_TX // "pinConfig" for CANB TX
// form pin_map.h
#define GPIO_30_GPIO30 0x00081C00U
#define GPIO_30_CANA_RX 0x00081C01U
#define GPIO_30_SPIB_SIMO 0x00081C03U
#define GPIO_30_OUTPUTXBAR7 0x00081C05U
#define GPIO_30_EQEP1_STROBE 0x00081C06U
#define GPIO_30_SD1_D4 0x00081C07U
#define GPIO_31_GPIO31 0x00081E00U
#define GPIO_31_CANA_TX 0x00081E01U
#define GPIO_31_SPIB_SOMI 0x00081E03U
#define GPIO_31_OUTPUTXBAR8 0x00081E05U
#define GPIO_31_EQEP1_INDEX 0x00081E06U
#define GPIO_31_SD1_C4 0x00081E07U
#define GPIO_31_FSIRXA_D1 0x00081E09U
GPIO配置函数细究
GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
from device.h
#define DEVICE_GPIO_CFG_CANRXA GPIO_30_CANA_RX // "pinConfig" for CANA RX
#define DEVICE_GPIO_CFG_CANTXA GPIO_31_CANA_TX // "pinConfig" for CANA TX
#define DEVICE_GPIO_CFG_CANRXB GPIO_10_CANB_RX // "pinConfig" for CANB RX
#define DEVICE_GPIO_CFG_CANTXB GPIO_8_CANB_TX // "pinConfig" for CANB TX
GPIO_setPinConfig(uint32_t pinConfig);
//! Configures the alternate function of a GPIO pin.
//!
//! \param pinConfig is the pin configuration value, specified as only one
//! of the \b GPIO_#_???? values.
//!
//! This function configures the pin mux that selects the peripheral function
//! associated with a particular GPIO pin. Only one peripheral function at a
//! time can be associated with a GPIO pin, and each peripheral function should
//! only be associated with a single GPIO pin at a time (despite the fact that
//! many of them can be associated with more than one GPIO pin).
GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD);
from device.h
#define DEVICE_GPIO_PIN_LED1 31U // GPIO number for LD2
#define DEVICE_GPIO_PIN_LED2 34U // GPIO number for LD3
#define DEVICE_GPIO_CFG_LED1 GPIO_31_GPIO31 // "pinConfig" for LD2
#define DEVICE_GPIO_CFG_LED2 GPIO_34_GPIO34 // "pinConfig" for LD3
GPIO_setPadConfig(uint32_t pin, uint32_t pinType)
//! Sets the pad configuration for the specified pin.
//!
//! \param pin is the identifying GPIO number of the pin.
//! \param pinType specifies the pin type.
//!
//! This function sets the pin type for the specified pin. The parameter
//! \e pinType can be the following values:
//!
//! - \b GPIO_PIN_TYPE_STD specifies a push-pull output or a floating input
//! - \b GPIO_PIN_TYPE_PULLUP specifies the pull-up is enabled for an input
//! - \b GPIO_PIN_TYPE_OD specifies an open-drain output pin
//! - \b GPIO_PIN_TYPE_INVERT specifies inverted polarity on an input
GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);
GPIO_setDirectionMode(uint32_t pin, GPIO_Direction pinIO);
//*****************************************************************************
//
//! Sets the direction and mode of the specified pin.
//!
//! \param pin is the identifying GPIO number of the pin.
//! \param pinIO is the pin direction mode.
//!
//! This function configures the specified pin on the selected GPIO port as
//! either input or output.
//!
//! The parameter \e pinIO is an enumerated data type that can be one of the
//! following values:
//!
//! - \b GPIO_DIR_MODE_IN
//! - \b GPIO_DIR_MODE_OUT
//!
//! where \b GPIO_DIR_MODE_IN specifies that the pin is programmed as an input
//! and \b GPIO_DIR_MODE_OUT specifies that the pin is programmed as an output.
//!
//! The pin is specified by its numerical value. For example, GPIO34 is
//! specified by passing 34 as \e pin.
#define DEVICE_GPIO_PIN_CANTXA 31U // GPIO number for CANTXA(引脚号)
#define DEVICE_GPIO_CFG_CANRXA GPIO_30_CANA_RX // "pinConfig" for CANA RX(引脚配置,pin_map.h文件中)
//*****************************************************************************
#define GPIO_PIN_TYPE_STD 0x0000U //!< Push-pull output or floating input
#define GPIO_PIN_TYPE_PULLUP 0x0001U //!< Pull-up enable for input
#define GPIO_PIN_TYPE_INVERT 0x0002U //!< Invert polarity on input
#define GPIO_PIN_TYPE_OD 0x0004U //!< Open-drain on output
#endif
//*****************************************************************************
//
//! Values that can be passed to GPIO_setDirectionMode() as the \e pinIO
//! parameter and returned from GPIO_getDirectionMode().
//
//*****************************************************************************
typedef enum
{
GPIO_DIR_MODE_IN, //!< Pin is a GPIO input
GPIO_DIR_MODE_OUT //!< Pin is a GPIO output
} GPIO_Direction;
设置引脚GPIO和设置引脚复用,gpio.h
GPIO输入输出:
GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD);
GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);
GPIO_writePin(DEVICE_GPIO_PIN_LED1, 0);
GPIO_readPin(uint32_t pin)
GPIO复用:
GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA);
C2000 驱动文件层次研究
(最好把文件打开对比着看,对文件结构里理解很到位,再配合上一篇建立工程,更好的理解了)
device.c,device.h ,driverlib.h 都是是TI做好的库函数
device.h 设备的引脚宏定义
driverlib.h 设备外设驱动的声明
//from devicelib.h
#include "inc/hw_memmap.h"
#include "adc.h"
#include "asysctl.h"
#include "can.h"
#include "cla.h"
#include "clb.h"
#include "clapromcrc.h"
#include "cmpss.h"
#include "cpu.h"
#include "cputimer.h"
#include "dac.h"
#include "dcc.h"
#include "dcsm.h"
#include "debug.h"
#include "dma.h"
#include "ecap.h"
#include "epwm.h"
#include "eqep.h"
#include "flash.h"
#include "fsi.h"
#include "gpio.h"
#include "hrcap.h"
#include "hrpwm.h"
#include "i2c.h"
#include "interrupt.h"
#include "lin.h"
#include "memcfg.h"
#include "pga.h"
#include "pin_map.h"
#include "pin_map_legacy.h"
#include "pmbus.h"
#include "sci.h"
#include "sdfm.h"
#include "spi.h"
#include "sysctl.h"
#include "version.h"
#include "xbar.h"
开头的 hw_memmap.h
// FILE: hw_memmap.h
//
// TITLE: Macros defining the memory map of the C28x.
最底层的寄存器宏定义,是E:\ti\c2000\C2000Ware_3_03_00_00\driverlib\f28004x\driverlib\inc,hw前缀的文件
// FILE: hw_adc.h
//
// TITLE: Definitions for the ADC registers.
再往上是 E:\ti\c2000\C2000Ware_3_03_00_00\driverlib\f28004x\driverlib 各种外设驱动文件
往上又是 E:\ti\c2000\C2000Ware_3_03_00_00\device_support\f28004x\common\include 的各种外设应用文件
编程时,写这两句,就把外设的驱动包括进来了
#include "driverlib.h"
#include "device.h"
再在工程中添加文件索引
E:\ti\c2000\C2000Ware_3_03_00_00\driverlib\f28004x\driverlib
在driverlib.h里面开头,#include "inc/hw_memmap.h",表示当前路径下inc文件夹里的hw_memmap.h,所以复制文件需要整个E:\ti\c2000\C2000Ware_3_03_00_00\driverlib\f28004x\driverlib下 的文件
再可以打开被#include "driverlib.h"引用的adc.h文件 ,开头就声明了,
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_adc.h"
#include "inc/hw_asysctl.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "cpu.h"
#include "debug.h"
发现 #include <stdbool.h> 这个文件就是编译器带的头文件了
所以需要在工程中添加文件索引
E:\ti\ccs1011\ccs\tools\compiler\ti-cgt-c2000_20.2.1.LTS\include
使用ADC与CAN外设初始化函数细究
//驱动里面没有这个函数,需要自己写
// initADCs - Function to configure and power up ADCs A and B.
//
void initADCs(void)
{
//
// Setup VREF as internal
//
ADC_setVREF(ADCA_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
ADC_setVREF(ADCB_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
//
// Set ADCCLK divider to /4
//
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
ADC_setPrescaler(ADCB_BASE, ADC_CLK_DIV_4_0);
//
// Set pulse positions to late
//
ADC_setInterruptPulseMode(ADCA_BASE, ADC_PULSE_END_OF_CONV);
ADC_setInterruptPulseMode(ADCB_BASE, ADC_PULSE_END_OF_CONV);
//
// Power up the ADCs and then delay for 1 ms
//
ADC_enableConverter(ADCA_BASE);
ADC_enableConverter(ADCB_BASE);
DEVICE_DELAY_US(1000);
}
from can.h
//
// Initialize the CAN controller
//
CAN_initModule(CANA_BASE);
TI的外设初始化也是醉了,ADC初始化自己写个函数,SPI外设,建了个E:\CCS_workplace\spi_ex1_loopback\CPU1_RAM\syscfg board.c,board.h
使用外设之前可以先看看示例工程,这样还方便一下
中断触发方法的研究
中断优先级