After publishing my last blog (blog #7) on 2 May I was trying to interface SD card with PSoC 62S4 device. For last three days I have spent more than 25 (twenty five) hours to successfully store and read image files from an SD card. First I tried with emFile Middleware that came with the ModusToolbox 3.0. After spending some time on it I realized that though emFile support SPI protocol for SD card, the Infineon licensed emFile only support Card Mode. Though Card Mode has higher speed than SPI, as my display shield contains an inbuilt SPI supported SD Card slot so I wanted to use that.
After some unsuccessful attempts with emFile I tried with Littlefs example program. But soon I understood that it also support Card Mode only. As HAL API provides SDHC (SD Host Controller) for interfacing SD card in Card Mode (or SDIO) and the API is very easy to understand, I changed my mind and collected an TF card adapter from Waveshare that support SDIO interfacing. After getting it hand I started reading related documents and web blogs to collect some more knowledge about SDIO interfacing. I tried to compile the emFile example code for the PSoC 62S4 Pioneer Kit but failed. I got same result for Littlefs. I first taught it could be solve by modifying the BSP but soon I understood that for supporting Card Mode the microcontroller requires an SDIO hardware block and PSoC 62S4 Pioneer Kit doesn't contain that block (Not 100% Sure Yet).
I was a bit frustrated knowing that and I came back to SPI again. After spending lots of hours on searching internet and debugging with the code I have been able to do basic communication between SD card and PSoC 62S4 microcontroller board. Now I am trying to glue it with the FatFS file system library. But as the deadline will reach within few hours I want to publish my work so far I completed. I know for making my project as a successful Learning Kit for my Kid an SD card interfacing is essential because the PSoC 62S4 device has no enough flash memory (no microcontroller has) to store graphics and audio. So, I have chosen SD card as an effective solution for that purpose.
If I can integrate my developed SPI SD card driver with FatFS filesystem I will publish it in my next blog. This is some response I received in Arduino serial monitor while developing the SPI driver for SD card.
A sample code for SD driver I developed using HAL API is attached below. The code needs some updates but still you can compile it and read the basic information from the SD card such as type and block size.
#include "cy_pdl.h"
#include "cyhal.h"
#include "cybsp.h"
#include <stdint.h>
#include "diskio.h"
#include "fatfs_sd.h"
#include "cy_retarget_io.h"
#define TRUE 1
#define FALSE 0
#define SD_CS_PIN CYBSP_D5
#define __SD_CS_OUT() cyhal_gpio_init(SD_CS_PIN, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, false)
#define __SD_CS_CLR() cyhal_gpio_write(SD_CS_PIN, false)
#define __SD_CS_SET() cyhal_gpio_write(SD_CS_PIN, true)
static volatile DSTATUS Stat = STA_NOINIT;
static uint8_t CardType;
static uint8_t PowerFlag = 0;
extern cyhal_spi_t mSPI;
/* SPI Chip Select */
static void SELECT(void)
{
__SD_CS_CLR();
}
/* SPI Chip Deselect */
static void DESELECT(void)
{
__SD_CS_SET();
}
/* SPI data transmission */
static void SPI_TxByte(BYTE data)
{
cyhal_spi_send(&mSPI, data);
}
/* SPI return type function for sending and receiving data */
static uint8_t SPI_RxByte(void)
{
uint8_t data;
data = 0;
cyhal_spi_recv(&mSPI, &data);
//printf("%d\r\n\n", data);
return data;
}
/* SPI pointer functions for sending and receiving data */
static void SPI_RxBytePtr(uint8_t *buff)
{
*buff = SPI_RxByte();
//buff = SPI_RxByte();
//printf("buff = %d\r\n\n", *buff);
}
/* SD card ready standby */
static uint8_t wait_not_busy(unsigned int timeout){
unsigned int tmr;
for(tmr = timeout*10; tmr; tmr--){
uint8_t d = SPI_RxByte();
if(d == 0xFF) return true;
cyhal_system_delay_us(100);
}
return false;
}
/* power on */
static void SD_PowerOn(void)
{
uint8_t cmd_arg[6];
uint32_t Count = 0x1FFF;
DESELECT();
for(int i = 0; i < 10; i++)
{
SPI_TxByte(0xFF);
}
/* SPI Chips Select */
SELECT();
/* Initial GO_IDLE_STATE state transition */
cmd_arg[0] = (CMD0 | 0x40);
cmd_arg[1] = 0;
cmd_arg[2] = 0;
cmd_arg[3] = 0;
cmd_arg[4] = 0;
cmd_arg[5] = 0x95;
/* send command */
for (int i = 0; i < 6; i++)
{
SPI_TxByte(cmd_arg[i]);
}
/* waiting for response */
while ((SPI_RxByte() != 0x01) && Count)
{
Count--;
}
DESELECT();
SPI_TxByte(0XFF);
PowerFlag = 1;
}
/* power off */
static void SD_PowerOff(void)
{
PowerFlag = 0;
}
/* Check power status */
static uint8_t SD_CheckPower(void)
{
/* 0=off, 1=on */
return PowerFlag;
}
static BYTE SD_ReadyWait (void)
{
BYTE d;
UINT tmr;
for(tmr = 5000; tmr; tmr--){
d = SPI_RxByte();
if(d == 0xFF) break;
cyhal_system_delay_us(100);
}
//printf("d = %x\r\n\n", d);
return (d == 0xFF) ? 1 : 0;
}
/* data packet reception */
static bool SD_RxDataBlock(BYTE *buff, UINT btr)
{
uint8_t token;
printf("from rx dtat block\r\n\n");
/* waiting for response till 100ms */
UINT tmr;
for(tmr = 1000; tmr ; tmr--){
token = SPI_RxByte();
//printf("token = %x\r\n\n", token);
if(token == 0xFE) break;
cyhal_system_delay_us(100);
}
/* Error handling when receiving tokens other than 0xFE */
if(token != 0xFE)
return FALSE;
/* Receive data into buffer */
do
{
//printf("from inside do blockk\r\n\n");
SPI_RxBytePtr(buff++);
SPI_RxBytePtr(buff++);
} while(btr -= 2);
SPI_RxByte(); /* Ignore CRC */
//printf("token = %x\r\n\n", token);
SPI_RxByte();
//printf("token = %x\r\n\n", token);
return TRUE;
}
/* data transfer packet */
#if _READONLY == 0
static bool SD_TxDataBlock(const BYTE *buff, BYTE token)
{
uint8_t resp = 0, wc;
uint8_t i = 0;
printf("from tx dtat block\r\n\n");
/* Waiting for SD card ready */
if (SD_ReadyWait() != 0xFF)
return FALSE;
/* token transfer */
SPI_TxByte(token);
/* If it is a data token */
if (token != 0xFD)
{
wc = 0;
/* 512 bytes data transmission */
do
{
SPI_TxByte(*buff++);
SPI_TxByte(*buff++);
} while (--wc);
SPI_RxByte(); /* CRC 무시 */
SPI_RxByte();
/* Receive date response */
while (i <= 64)
{
resp = SPI_RxByte();
/* Error response handling */
if ((resp & 0x1F) == 0x05)
break;
i++;
}
/* Clear the SPI receive buffer */
while (SPI_RxByte() == 0);
}
if ((resp & 0x1F) == 0x05)
return TRUE;
else
return FALSE;
}
#endif /* _READONLY */
/* Send CMD Packet */
static BYTE SD_SendCmd(BYTE cmd, DWORD arg)
{
uint8_t crc, res;
SELECT();
/* SD card standby */
wait_not_busy(300);
SPI_TxByte(cmd | 0x40);
int8_t s;
for(s = 24; s >= 0; s -= 8){
SPI_TxByte(arg >> s);
}
/* CRC preparation per instruction */
crc = 0xFF;
if (cmd == CMD0)
crc = 0x95; /* CRC for CMD0(0) */
if (cmd == CMD8)
crc = 0x87; /* CRC for CMD8(0x1AA) */
/* CRC send */
SPI_TxByte(crc);
uint8_t i;
for(i = 0; ((res = SPI_RxByte()) & 0x80) && i != 0xFF; i++);
//printf("Res from sd send command = %d\r\n\n", res);
return res;
}
uint8_t SD_cardAcmd(uint8_t cmd, uint32_t arg) {
SD_SendCmd(CMD55, 0);
return SD_SendCmd(cmd, arg);
}
/*-----------------------------------------------------------------------
Global functions used in fatfs
Used in the user_diskio.c file
-----------------------------------------------------------------------*/
/* SD card initialization */
DSTATUS SD_disk_initialize(BYTE drv)
{
/* Supports only one type of drive */
if(drv)
return STA_NOINIT;
uint8_t n, type, ocr[4];
UINT tmr;
uint8_t status;
uint32_t arg;
DESELECT();
uint8_t i;
for(i = 0; i < 10; i++){
SPI_TxByte(0xFF);
}
SELECT();
for(tmr = SD_INIT_TIMEOUT*10; tmr; tmr--){
if((status = SD_SendCmd(CMD0, 0)) == R1_IDLE_STATE){
break;
}
cyhal_system_delay_us(100);
}
// check SD version
if ((SD_SendCmd(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
type = SD_CARD_TYPE_SD1;
printf("SD_CARD_TYPE_SD1\r\n\n");
}
else {
// only need last byte of r7 response
for (i = 0; i < 4; i++) {
status = SPI_RxByte();
}
if (status != 0xAA) {
//error(SD_CARD_ERROR_CMD8);
goto fail;
}
type = SD_CARD_TYPE_SD2;
printf("SD_CARD_TYPE_SD2\r\n\n");
}
arg = type == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
//printf("Arguments = %x\r\n\n", arg);
SD_SendCmd(CMD55, 0);
status = SD_SendCmd(ACMD41, arg);
SD_SendCmd(CMD55, 0);
status = SD_SendCmd(ACMD41, arg);
//printf("command acmd41 = %d\r\n\n", status);
for(tmr = SD_INIT_TIMEOUT*10; tmr; tmr--){
if((status = SD_cardAcmd(ACMD41, arg)) == R1_READY_STATE){
break;
}
cyhal_system_delay_us(100);
}
printf("SD_CARD Status = %d\r\n\n", status);
if(tmr <= 0){
printf("SD_CARD Status = not ready\r\n\n");
//error(SD_CARD_ERROR_ACMD41);
goto fail;
}
// if SD2 read OCR register to check for SDHC card
if (type == SD_CARD_TYPE_SD2) {
if (SD_SendCmd(CMD58, 0)) {
//error(SD_CARD_ERROR_CMD58);
goto fail;
}
if ((SPI_RxByte() & 0xC0) == 0xC0) {
type = SD_CARD_TYPE_SDHC;
}
// discard rest of ocr - contains allowed voltage range
for (i = 0; i < 3; i++) {
SPI_RxByte();
}
}
CardType = type;
if (type) { /* OK */
Stat &= ~STA_NOINIT;
printf("clock high\r\n\n");
} else { /* Failed */
Stat = STA_NOINIT;
printf("failed\r\n\n");
}
DESELECT();
return Stat;
fail:
DESELECT();
return false;
}
//------------------------------------------------------------------------------
/** Wait for start block token */
static uint8_t waitStartBlock(void) {
uint32_t tmr;
uint8_t status;
for(tmr = SD_READ_TIMEOUT*10; tmr; tmr--){
if((status = SPI_RxByte()) != 0xFF) break;
cyhal_system_delay_us(100);
}
if(tmr <= 0){
//error(SD_CARD_ERROR_READ_TIMEOUT);
goto fail;
}
if (status != DATA_START_BLOCK) {
//error(SD_CARD_ERROR_READ);
goto fail;
}
return true;
fail:
DESELECT();
return false;
}
uint8_t readRegister(uint8_t cmd, void* buf){
uint8_t* dst = (uint8_t*)(buf);
if (SD_SendCmd(cmd, 0)) {
//error(SD_CARD_ERROR_READ_REG);
goto fail;
}
if (!waitStartBlock()) {
goto fail;
}
// transfer data
uint16_t i;
for (i = 0; i < 16; i++) {
dst[i] = SPI_RxByte();
}
SPI_RxByte();; // get first crc byte
SPI_RxByte();; // get second crc byte
DESELECT();
return true;
fail:
DESELECT();
return false;
}
uint8_t readCSD(csd2_t* csd) {
return readRegister(CMD9, csd);
}
uint32_t cardSize(void) {
csd2_t csd;
if (!readCSD(&csd)) {
return 0;
}
if(csd.csd_ver == 1) {
uint32_t c_size = ((uint32_t)csd.c_size_high << 16)
| (csd.c_size_mid << 8) | csd.c_size_low;
return (c_size + 1) << 10;
}
else {
//error(SD_CARD_ERROR_BAD_CSD);
return 0;
}
}
/* Check disk status */
DSTATUS SD_disk_status(BYTE drv)
{
printf("from disk status block\r\n\n");
if (drv)
return STA_NOINIT;
return Stat;
}
/* sector read */
DRESULT SD_disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
{
printf("from disk read block\r\n\n");
if (pdrv || !count)
return RES_PARERR;
if (Stat & STA_NOINIT)
return RES_NOTRDY;
if (!(CardType & 4))
sector *= 512;
SELECT();
if (count == 1)
{
//printf("inside count 1\r\n\n");
if ((SD_SendCmd(CMD17, sector) == 0) && SD_RxDataBlock(buff, 512))
count = 0;
//printf("inside count 0\r\n\n");
}
else
{
if (SD_SendCmd(CMD18, sector) == 0)
{
do {
if (!SD_RxDataBlock(buff, 512))
break;
buff += 512;
} while (--count);
SD_SendCmd(CMD12, 0);
}
}
DESELECT();
SPI_RxByte();
//printf(" count = %d\r\n\n", count);
return count ? RES_ERROR : RES_OK;
}
#if _READONLY == 0
DRESULT SD_disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
{
printf("from disk write block\r\n\n");
if (pdrv || !count)
return RES_PARERR;
if (Stat & STA_NOINIT)
return RES_NOTRDY;
if (Stat & STA_PROTECT)
return RES_WRPRT;
if (!(CardType & 4))
sector *= 512;
SELECT();
if (count == 1)
{
if ((SD_SendCmd(CMD24, sector) == 0) && SD_TxDataBlock(buff, 0xFE))
count = 0;
}
else
{
if (CardType & 2)
{
SD_SendCmd(CMD55, 0);
SD_SendCmd(CMD23, count);
}
if (SD_SendCmd(CMD25, sector) == 0)
{
do {
if(!SD_TxDataBlock(buff, 0xFC))
break;
buff += 512;
} while (--count);
if(!SD_TxDataBlock(0, 0xFD))
{
count = 1;
}
}
}
DESELECT();
SPI_RxByte();
return count ? RES_ERROR : RES_OK;
}
#endif
/* other functions */
DRESULT SD_disk_ioctl(BYTE drv, BYTE ctrl, void *buff)
{
printf("from ioct block\r\n\n");
DRESULT res;
BYTE n, csd[16], *ptr = buff;
WORD csize;
if (drv)
return RES_PARERR;
res = RES_ERROR;
if (ctrl == CTRL_POWER)
{
switch (*ptr)
{
case 0:
if (SD_CheckPower())
SD_PowerOff(); /* Power Off */
res = RES_OK;
break;
case 1:
SD_PowerOn(); /* Power On */
res = RES_OK;
break;
case 2:
*(ptr + 1) = (BYTE) SD_CheckPower();
res = RES_OK; /* Power Check */
break;
default:
res = RES_PARERR;
}
}
else
{
if (Stat & STA_NOINIT)
return RES_NOTRDY;
SELECT();
switch (ctrl)
{
case GET_SECTOR_COUNT:
/* The number of sectors in the SD card (DWORD) */
if ((SD_SendCmd(CMD9, 0) == 0) && SD_RxDataBlock(csd, 16))
{
if ((csd[0] >> 6) == 1)
{
/* SDC ver 2.00 */
csize = csd[9] + ((WORD) csd[8] << 8) + 1;
*(DWORD*) buff = (DWORD) csize << 10;
}
else
{
/* MMC or SDC ver 1.XX */
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((WORD) csd[7] << 2) + ((WORD) (csd[6] & 3) << 10) + 1;
*(DWORD*) buff = (DWORD) csize << (n - 9);
}
res = RES_OK;
}
break;
case GET_SECTOR_SIZE:
/* unit size of sector (WORD) */
*(WORD*) buff = 512;
res = RES_OK;
break;
case CTRL_SYNC:
/* sync write */
if (SD_ReadyWait() == 0xFF)
res = RES_OK;
break;
case MMC_GET_CSD:
/* CSD receive information (16 bytes) */
if (SD_SendCmd(CMD9, 0) == 0 && SD_RxDataBlock(ptr, 16))
res = RES_OK;
break;
case MMC_GET_CID:
/* CID receive information (16 bytes) */
if (SD_SendCmd(CMD10, 0) == 0 && SD_RxDataBlock(ptr, 16))
res = RES_OK;
break;
case MMC_GET_OCR:
/* OCR receive information (4 bytes) */
if (SD_SendCmd(CMD58, 0) == 0)
{
for (n = 0; n < 4; n++)
{
*ptr++ = SPI_RxByte();
}
res = RES_OK;
}
default:
res = RES_PARERR;
}
DESELECT();
SPI_RxByte();
}
return res;
}
In this blog, I will show how I developed the firmware for dual core PSoC 62S4 Pioneer Kit for my project. In previous blogs I explain every parts separately with code and explanation. Here I actually adding all the previous code and functionality all together. I used the CM0+ core for reading CapSense buttons and slider. The response is then sent to CM4 core. CM4 core processed messages received from the CM0+ for driving and updating the display. It also reads the necessary images and audio files from SD card using SPI port. For successful compilation of the code we needs few libraries. The emFile and retarget-io library was installed in the CM4 core and Capsense library is installed to CM0+ core.
Image below shows the core wise installed library.
As currently SD card part is not completed yet, I only used text and symbol for showing Numbers/Digits and few small bmp graphics for displaying some Alphabets. For memory limitation I could not add enough alphabets and learning materials. Same is happened for sound. Here is a main code snippet for CM4 core that is for logic and graphics functions:
int main(void)
{
cy_rslt_t result;
/* Init the IPC communication for CM4 */
setup_ipc_communication_cm4();
/* Initialize the device and board peripherals */
result = cybsp_init() ;
handle_error(result);
/* Enable global interrupts */
__enable_irq();
/* Initialize retarget-io to use the debug UART port */
cy_retarget_io_init(CYBSP_DEBUG_UART_TX, CYBSP_DEBUG_UART_RX, CY_RETARGET_IO_BAUDRATE);
/* Register the Message Callback */
Cy_IPC_Pipe_RegisterCallback(CY_IPC_EP_CYPIPE_CM4_ADDR,
cm4_msg_callback,
IPC_CM0_TO_CM4_CLIENT_ID);
result = cyhal_spi_init(&mSPI,CYBSP_SPI_MOSI,CYBSP_SPI_MISO,CYBSP_SPI_CLK,
NC,NULL,BITS_PER_FRAME,
CYHAL_SPI_MODE_11_MSB,false);
handle_error(result);
result = cyhal_spi_set_frequency(&mSPI, SPI_FREQ_HZ);
handle_error(result);
GUI_Init();
menu_screen();
int menu = 0, number = 0;
for (;;)
{
//cyhal_syspm_sleep();
/* Check if a message was received from CM0+ */
if (msg_flag)
{
msg_flag = false;
int value = (unsigned int) msg_value;
if(value==1) {
if(menu==0) number = 1;
menu++;
if(menu > 25) menu = 25;
}
else if(value==0) {
if(menu==0){
menu = 3;
number = 0;
}
menu--;
if(menu < 0) menu = 0;
}
else if(value > 1){
value = value/10;
menu = value;
}
/* Print random number received from CM0+ */
//printf("Number value = %d\n\r", number);
if(menu == 0) menu_screen();
else if(menu == 1) number_screen();
else if(menu == 2) number?display_number(1, 3):display_a();
else if(menu == 3) number?display_number(2, 1):display_b();
else if(menu == 4) number?display_number(3, 2):display_c();
else if(menu == 5) number?display_number(4, 4):display_d();
else if(menu == 6) number?display_number(5, 5):display_e();
else if(menu == 7) number?display_number(6, 6):display_f();
}
}
}
/*******************************************************************************
* Function Name: cm4_msg_callback
********************************************************************************
* Summary:
* Callback function to execute when receiving a message from CM0+ to CM4.
*
* Parameters:
* msg: message received
*
*******************************************************************************/
void cm4_msg_callback(uint32_t *msg)
{
ipc_msg_t *ipc_recv_msg;
if (msg != NULL)
{
/* Cast received message to the IPC message structure */
ipc_recv_msg = (ipc_msg_t *) msg;
/* Extract the message value */
msg_value = ipc_recv_msg->value;
/* Set message flag */
msg_flag = true;
}
}
void display_a(void){
GUI_Clear();
GUI_DrawBitmap(&bma_apple, 220, 112);
GUI_DrawBitmap(&bma, 0, 0);
}
void display_b(void){
GUI_Clear();
GUI_DrawBitmap(&bmball, 220, 141);
GUI_DrawBitmap(&bmb, 0, 0);
}
void display_c(void){
;
}
void display_d(void){
;
}
void display_e(void){
;
}
void display_f(void){
;
}
/*
void start_screen(void) {
GUI_SetBkColor(GUI_BLACK);
GUI_Clear();
GUI_SetColor(GUI_WHITE);
GUI_SetFont(&GUI_Font32B_ASCII);
//GUI_SetFont(&GUI_Font32B_1);
GUI_DispStringHCenterAt("Kids Learning Kit", 160, 20);
BUTTON_Handle dButton, cButton;
GUI_SetFont(&GUI_Font8x16);
GUI_DispStringHCenterAt("Touch a Capsense Button to Start", 160, 140);
dButton = BUTTON_Create(20, 180, 100, 50, GUI_ID_OK, WM_CF_SHOW);
cButton = BUTTON_Create(200, 180, 100, 50, GUI_ID_OK, WM_CF_SHOW);
//BUTTON_SetFont(dButton, &GUI_Font20B_ASCII);
//BUTTON_SetFont(dButton, &GUI_Font20B_1);
BUTTON_SetFont(dButton, &GUI_Font20_ASCII);
BUTTON_SetText(dButton, "Numbers");
BUTTON_SetFont(cButton, &GUI_Font20_ASCII);
BUTTON_SetText(cButton, "Alphabets");
while (GUI_WaitKey() != GUI_ID_OK);
//BUTTON_Delete(hButton);
//GUI_ClearRect(0, 50, 319, 239);
//GUI_Delay(1000);
}
*/
void menu_screen(){
GUI_SetBkColor(GUI_BLACK);
GUI_Clear();
GUI_SetColor(GUI_WHITE);
GUI_SetFont(&GUI_Font32B_ASCII);
//GUI_SetFont(&GUI_Font32B_1);
GUI_DispStringHCenterAt("Kids Learning Kit", 160, 20);
GUI_SetFont(&GUI_Font8x16);
GUI_DispStringHCenterAt("Touch a Capsense Button to Start", 160, 120);
//GUI_SetColor(GUI_RED);
GUI_FillCircle(70, 175, 30);
GUI_FillCircle(240, 175, 30);
GUI_SetColor(GUI_BLUE);
GUI_FillCircle(70, 175, 25);
GUI_FillCircle(240, 175, 25);
GUI_SetColor(GUI_WHITE);
GUI_SetFont(&GUI_Font20_ASCII);
GUI_DispStringHCenterAt("Numbers", 70, 210);
GUI_DispStringHCenterAt("Alphabets", 240, 210);
}
void number_screen(void){
GUI_SetBkColor(GUI_BLACK);
GUI_Clear();
GUI_SetColor(GUI_WHITE);
GUI_SetFont(&GUI_Font32B_ASCII);
//GUI_SetFont(&GUI_Font32B_1);
//GUI_SetFont(&GUI_Font);
GUI_DispStringHCenterAt("Numbers", 160, 20);
GUI_SetFont(&GUI_Font8x16);
GUI_DispStringHCenterAt("Use Slider (>>>) to Change Color", 160, 100);
GUI_SetFont(&GUI_Font8x16);
GUI_DispStringHCenterAt("Touch Capsense Button to Start", 160, 120);
GUI_FillCircle(70, 175, 30);
GUI_FillCircle(240, 175, 30);
GUI_SetColor(GUI_BLUE);
GUI_FillCircle(70, 175, 25);
GUI_FillCircle(240, 175, 25);
GUI_SetColor(GUI_WHITE);
GUI_SetFont(&GUI_Font20_ASCII);
GUI_DispStringHCenterAt("Next", 70, 210);
GUI_DispStringHCenterAt("Back", 240, 210);
}
void display_number(int digit, int color){
GUI_SetBkColor(GUI_BLACK);
GUI_Clear();
switch(color){
case 0:
GUI_SetColor(GUI_WHITE);
break;
case 1:
GUI_SetColor(GUI_RED);
break;
case 2:
GUI_SetColor(GUI_BLUE);
break;
case 3:
GUI_SetColor(GUI_YELLOW);
break;
case 4:
GUI_SetColor(GUI_GREEN);
break;
case 5:
GUI_SetColor(GUI_MAGENTA);
break;
case 6:
GUI_SetColor(GUI_GRAY);
break;
case 7:
GUI_SetColor(GUI_CYAN);
break;
}
GUI_SetFont(&GUI_FontD80);
GUI_DispDecAt(digit, 30, 30, 1);
//GUI_SetColor(GUI_BLUE);
draw_symbol(digit);
}
void draw_symbol(int digit){
switch(digit+1){
case 0:
GUI_SetColor(GUI_WHITE);
break;
case 1:
GUI_SetColor(GUI_RED);
break;
case 2:
GUI_SetColor(GUI_BLUE);
break;
case 3:
GUI_SetColor(GUI_YELLOW);
break;
case 4:
GUI_SetColor(GUI_GREEN);
break;
case 5:
GUI_SetColor(GUI_MAGENTA);
break;
case 6:
GUI_SetColor(GUI_CYAN);
break;
}
switch(digit){
case 0:
//GUI_DrawCircle(10, 50, 20);
break;
case 1:
GUI_FillCircle(200, 160, 45);
GUI_SetColor(GUI_RED);
GUI_FillCircle(180, 140, 5);
GUI_FillCircle(220, 140, 5);
GUI_FillEllipse(200, 160, 7, 5);
break;
case 2:
draw_triangle();
break;
case 3:
GUI_FillRect(50, 140, 110, 200);
GUI_FillRect(130, 140, 190, 200);
GUI_FillRect(210, 140, 270, 200);
break;
case 4:
GUI_FillCircle(40, 170, 35);
GUI_FillCircle(120, 170, 35);
GUI_FillCircle(200, 170, 35);
GUI_FillCircle(280, 170, 35);
break;
case 5:
GUI_FillRect(130, 70, 190, 130);
GUI_FillRect(210, 70, 270, 130);
GUI_FillRect(130, 150, 190, 210);
GUI_FillRect(210, 150, 270, 210);
GUI_FillRect(50, 150, 110, 210);
break;
}
}
void draw_triangle(){
const GUI_POINT aPoints[] = {
{ 40, 20}, //x1, y1
{ 0, 20},//x1, y2
{ 20, 0} //
};
GUI_POINT aEnlargedPoints[GUI_COUNTOF(aPoints)];
GUI_EnlargePolygon(aEnlargedPoints, aPoints, GUI_COUNTOF(aPoints), 3 * 5);
//GUI_FillPolygon(aPoints, GUI_COUNTOF(aPoints), 140, 110);
GUI_FillPolygon(aEnlargedPoints, GUI_COUNTOF(aPoints), 90, 160);
GUI_FillPolygon(aEnlargedPoints, GUI_COUNTOF(aPoints), 220, 160);
}
The code structure in the ModusToolbox Eclipse IDE project is as follows. Of course the code can be better organize but I did not focus on this at this moment.
Application-level block diagram added below shows how the two processor cores and other peripheral blocks of PSoC 62S4 MCU are interconnected and utilized in my project for successful application.
Following image represents the firmware flowchart:
This is demo video of the working project:
The GitHub link for full source code is given below.
Kids_Learning_Kit_PSoC-62S4_Dual_Core_App
All Previous Blogs:
- Blog#7: Sending Capsense Data from CM0+ to CM4 using IPC Pipe
- Blog#6: Inter-core communication using IPC Pipe
- Blog#5: Using emWin & ModusToolbox for Displaying Bitmap Image
- Blog#4: Using emWin Middleware for Driving TFT Display
- Blog#3: Interfacing 2.8 inch LCD with PSoC 6 & ModusToolbox 3.0
- Blog#2: Getting Started with PSoC 62S4 Pioneer Kit & ModusToolbox 3.0
- Blog#1: Introduction