cpu1은 cpu2 또는 cm을 부트 시켜줄 수 있다. 또한 부트 전 pin mux 세팅을 하고 peripheral을 할당해 줄 수 있는 것도 cpu1 뿐이다.
CPU1 코드
#include "driverlib.h"
#include "device.h"
void Board_init();
void SCI_config();
void SPI_config();
void main(void)
{
Device_init();
Device_initGPIO();
Interrupt_initModule();
Interrupt_initVectorTable();
// syscfg툴로 생성된 Board.c의 함수가 아니라 생성되는 코드를 참고해 직접 작성한 함수이다. 이 편이 직관성이 높아서 좋은 것 같다.
Board_init();
//
// Boot CPU2 core
// 부트모드에 따라 CPU2를 플래시 부트 또는 램 부트한다.
#ifdef _FLASH
Device_bootCPU2(BOOTMODE_BOOT_TO_FLASH_SECTOR0);
#else
Device_bootCPU2(BOOTMODE_BOOT_TO_M0RAM);
#endif
EINT;
ERTM;
for(;;)
{
GPIO_togglePin(DEVICE_GPIO_PIN_LED1);
DEVICE_DELAY_US(1000000);
}
}
void Board_init()
{
EALLOW;
LED_init();
SCI_config();
SPI_config();
EDIS;
}
void LED_init()
{
//
// Initialize GPIO and configure the GPIO pin as a push-pull output
// LED1, LED2 핀 config
GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD);
GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(DEVICE_GPIO_PIN_LED2, GPIO_PIN_TYPE_STD);
GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED2, GPIO_DIR_MODE_OUT);
//
// Configure CPU2 to control the LED GPIO
// LED2 핀의 MasterCore를 CPU2로 설정
GPIO_setMasterCore(DEVICE_GPIO_PIN_LED2, GPIO_CORE_CPU2);
// default MasterCore가 CPU1이니까 LED1핀을 위한 MasterCore는 설정해줄 필요가 없다.
}
void SCI_config()
{
//
// Configuration for the SCI Rx/Tx pin.
// SCI RX/TX 핀 config
GPIO_setPinConfig(DEVICE_GPIO_CFG_SCIRXDA);
GPIO_setPinConfig(DEVICE_GPIO_CFG_SCITXDA);
//
// Hand-over the SCIA module access to CPU2
// SCIA 모듈을 CPU2에 연결
SysCtl_selectCPUForPeripheral(SYSCTL_CPUSEL5_SCI, 1, SYSCTL_CPUSEL_CPU2);
}
void SPI_config()
{
// CS핀 설정. 해당 GPIO핀의 MasterCore를 CPU2로 설정
// GPIO103 -> mySDCardCS Pinmux
GPIO_setPinConfig(GPIO_103_GPIO103);
GPIO_writePin(103, 1);
GPIO_setPadConfig(103, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(103, GPIO_QUAL_SYNC);
GPIO_setDirectionMode(103, GPIO_DIR_MODE_OUT);
GPIO_setMasterCore(103, GPIO_CORE_CPU2);
//
// SPIC -> mySDCardSPI Pinmux
// SPIC 모듈을 설정하고 CPU2에 연결
GPIO_setPinConfig(GPIO_100_SPIC_SIMO);
GPIO_setPadConfig(100, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(100, GPIO_QUAL_ASYNC);
GPIO_setPinConfig(GPIO_101_SPIC_SOMI);
GPIO_setPadConfig(101, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(101, GPIO_QUAL_ASYNC);
GPIO_setPinConfig(GPIO_102_SPIC_CLK);
GPIO_setPadConfig(102, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(102, GPIO_QUAL_ASYNC);
SysCtl_selectCPUForPeripheral(SYSCTL_CPUSEL6_SPI, 3, SYSCTL_CPUSEL_CPU2);
}
각 페리페럴에 연결될 CPU를 선택할 수 있는 CPUSELx 레지스터의 구성은 다음과 같다.
매뉴얼을 읽어보니 CPU2 부트 전에 페리페럴의 권한을 넘겨줘야 하는것 같다.(CPU2가 부트되자마자 device init()함수 안에서 enable peripheral clocks 하므로) 이걸 모르고 부트 후에 CPU2에 권한을 주었는데 작동이 되긴 했었다. CPUSEL 레지스터는 EALLOW 보호를 받는다.
그리고 이것도 나중에 안건데 SysCtl_selectCPUForPeripheral() 함수의 설명을 읽어보니 SysCtl_selectCPUForPeripheralInstance() 함수를 쓰는 것을 추천한다고 한다. 매개변수가 2개로 줄었긴한데 사용법은 크게 다르지 않다.
CPU2 코드
#include "driverlib.h"
#include "device.h"
#include <stdio.h>
#include <stdarg.h>
uint32_t uartPrintf(uint8_t ch, char *fmt, ...);
void board_init();
void SCI_init();
void CS_init();
void SPI_init();
void main(void)
{
uint16_t loopCount = 0;
Device_init();
Device_initGPIO();
Interrupt_initModule();
Interrupt_initVectorTable();
// 이것도 syscfg 툴로 생성된 코드를 참조해 직접 작성한 함수이다.
board_init();
EINT;
ERTM;
for(;;)
{
GPIO_togglePin(DEVICE_GPIO_PIN_LED2);
uartPrintf(SCIA_BASE, "Hello World %d\n", loopCount++);
DEVICE_DELAY_US(1000000);
}
}
void board_init()
{
SCI_init();
SPI_init();
}
void SCI_init()
{
// SCI port software reset 후 설정, 다시 software reset
SCI_performSoftwareReset(SCIA_BASE);
// SCI 설정
SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200, (SCI_CONFIG_WLEN_8 |
SCI_CONFIG_STOP_ONE |
SCI_CONFIG_PAR_NONE));
SCI_resetChannels(SCIA_BASE);
SCI_resetRxFIFO(SCIA_BASE);
SCI_resetTxFIFO(SCIA_BASE);
SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_TXFF | SCI_INT_RXFF);
SCI_enableFIFO(SCIA_BASE);
SCI_enableModule(SCIA_BASE);
SCI_performSoftwareReset(SCIA_BASE);
}
// 칩셀렉트 핀 init
void CS_init()
{
GPIO_writePin(103, 1);
GPIO_setPadConfig(103, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(103, GPIO_QUAL_SYNC);
GPIO_setDirectionMode(103, GPIO_DIR_MODE_OUT);
}
void SPI_init()
{
// SPI 모듈 disable 후 설정, 다시 enable
SPI_disableModule(SPIC_BASE);
SPI_setConfig(SPIC_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA1,
SPI_MODE_MASTER, 12500000, 8);
SPI_enableFIFO(SPIC_BASE);
SPI_disableLoopback(SPIC_BASE);
SPI_setEmulationMode(SPIC_BASE, SPI_EMULATION_STOP_AFTER_TRANSMIT);
SPI_enableModule(SPIC_BASE);
}
// printf 함수로 시리얼 터미널에 출력하기 위한 함수
uint32_t uartPrintf(uint8_t ch, char *fmt, ...)
{
char buf[256];
va_list args;
int len;
uint32_t ret = 0;
va_start(args, fmt);
len = vsnprintf(buf, 256, fmt, args);
SCI_writeCharArray(ch, (uint16_t*)buf, len);
//ret = uartWrite(ch, (uint8_t *)buf, len);
va_end(args);
return ret;
}
참고로 CPU2 프로젝트 설정에서 Predefined Symbol에 CPU2가 선언되어있으면 Device_init() 함수에서 수행되는 코드는
SysCtl_disableWatchdog(); // 워치독 disable
Device_enableAllPeripherals(); // 모든 peripheral clock enable
Device_initGPIO(); // GPIO pin locks 해제 및 enable Pull ups
그리고 플래시 부트인 경우 램 실행 함수들을 복사하고 flash initialization 함수를 호출하는 것 뿐이다.
'임베디드 개발 > TMS320F2838x (C28x)' 카테고리의 다른 글
TMS320F28388D ] DMA 예제 (0) | 2022.12.11 |
---|---|
TMS320F28388D ] DMA 파악하기 (0) | 2022.12.11 |
TMS320F28388D ] 타이머, Timer Interrupt 사용하기 (0) | 2022.12.05 |
TMS320F28388D ] Watchdog Timer 사용하기 (1) | 2022.12.03 |
TMS320F28388D ] FLASH Build 와 RAM Build 같이 사용하는 .cmd 파일 만들기 (3) | 2022.12.01 |