PSoC 6 pioneer kit multi library code for emwin driven tft display, capsense and mechanical button input.

Dependencies:   PinDetect

main.cpp

Committer:
reedas
Date:
2019-10-18
Revision:
3:1edcda6af8df
Parent:
2:02954bc28fc5

File content as of revision 3:1edcda6af8df:

#include "mbed.h"
#include "GUI.h"
#include "cy8ckit_028_tft.h"
#define Cy_SysLib_Delay wait_ms
#include "cy_pdl.h"
#include "cycfg_capsense.h"
#include "cycfg.h"
#include "PinDetect.h"

DigitalOut ledGreen(LED_GREEN);
DigitalIn  sw2(SWITCH2, PullUp);
DigitalOut ledRed(LED_RED);
DigitalOut userLed(LED4); /* Amber LED */
DigitalOut ledBlue(LED_BLUE);
DigitalOut ledBlue2(P13_4);
DigitalOut ledGreen2(P13_3);
DigitalOut ledRed2(P13_2);
PwmOut myPwm(LED5); /* Red Ststus LED */

PinDetect pb2(P0_4);

/* Macros for switch press status */
#define BTN_PRESSED        (0u)
#define BTN_RELEASED       (1u)

/***************************************************************************
* Global constants
***************************************************************************/
#define SLIDER_NUM_TOUCH                        (1u)    /* Number of touches on the slider */
#define nLED_OFF                                (1u)
#define nLED_ON                                 (0u)
#define LED_OFF                                 (0u)
#define LED_ON                                  (1u)
#define CAPSENSE_SCAN_PERIOD_MS                 (20u)   /* milliseconds */


/***************************************
* Function Prototypes
**************************************/
void RunCapSenseScan(void);
void InitTunerCommunication(void);
void ProcessTouchStatus(void);
void EZI2C_InterruptHandler(void);
void CapSense_InterruptHandler(void);
void CapSenseEndOfScanCallback(cy_stc_active_scan_sns_t * ptrActiveScan);
void InitCapSenseClock(void);
void LED_Init(void);
void Display_Init(void);
void CapSense_Init(void);
void Button_Init(void);

/*******************************************************************************
* Interrupt configuration
*******************************************************************************/
const cy_stc_sysint_t CapSense_ISR_cfg = {
    .intrSrc = CYBSP_CSD_IRQ,
    .intrPriority = 4u
};

const cy_stc_sysint_t EZI2C_ISR_cfg = {
    .intrSrc = CYBSP_CSD_COMM_IRQ,
    .intrPriority = 3u
};


/*******************************************************************************
* Global variables
*******************************************************************************/
//DigitalOut ledRed(LED_RED);
Semaphore capsense_sem;
EventQueue queue;
cy_stc_scb_ezi2c_context_t EZI2C_context;
uint32_t prevBtn0Status = 0u;
uint32_t prevBtn1Status = 0u;
uint32_t prevSliderPos = 0u;
bool    sw2Pressed = false;
bool    prevSw2Pressed = false;
bool    sw2ToggleStatus = false;
bool    btn0ToggleStatus = false;
bool    btn1ToggleStatus = false;


/* External global references */
//extern GUI_CONST_STORAGE GUI_BITMAP bmCypressLogo_1bpp;

extern GUI_CONST_STORAGE GUI_BITMAP bmExampleImage;
extern GUI_CONST_STORAGE GUI_BITMAP bmCypressLogo;

// Callback routine is interrupt activated by a debounced pb1 hit
void pb2_hit_callback (void)
{
//   printf("Count is %d\n", ++countit);
    sw2Pressed = true;
}
// Callback routine is interrupt activated by a debounced pb1 hit
void pb2_released_callback (void)
{
//   printf("Count is %d\n", ++countit);
    sw2Pressed = false;
}
/*******************************************************************************
* Function Name: bool IsBtnClicked
********************************************************************************
*
* Summary: This non-blocking function implements SW2 button click check.
*
* Parameters:
*  None
*
* Return:
*  Status of the SW2 button:
*  true when button was pressed and then released and
*  false in other cases
*
* This code is not used in this version of the program as PinDetect Library
* is employed to debounce the switch.
*
*******************************************************************************/
/*
 * bool IsBtnClicked(void)
 * {
 *     int currBtnState;
 *     static int prevBtnState  = BTN_RELEASED;
 * 
 *     bool result = false;
 * 
 *     currBtnState = sw2;
 * 
 *     if((prevBtnState == BTN_RELEASED) && (currBtnState == BTN_PRESSED)) {
 *         result = true;
 *     }
 * 
 *     prevBtnState = currBtnState;
 * 
 *     wait_ms(5);
 * 
 *     return result;
 * }
 */
/*****************************************************************************
* Function Name: RunCapSenseScan()
******************************************************************************
* Summary:
*   This function starts the scan, and processes the touch status. It is
* periodically called by an event dispatcher.
*
*****************************************************************************/
void RunCapSenseScan(void)
{
    Cy_CapSense_ScanAllWidgets(&cy_capsense_context);
    capsense_sem.acquire();
    Cy_CapSense_ProcessAllWidgets(&cy_capsense_context);
    Cy_CapSense_RunTuner(&cy_capsense_context);
    ProcessTouchStatus();
}


/*******************************************************************************
* Function Name: InitTunerCommunication
********************************************************************************
*
* Summary:
*   This function performs the following functions:
*       - Initializes SCB block for operation in EZI2C mode
*       - Configures EZI2C pins
*       - Configures EZI2C clock
*       - Sets communication data buffer to CapSense data structure
*
*******************************************************************************/
void InitTunerCommunication(void)
{
    /* Initialize EZI2C pins */
    Cy_GPIO_Pin_Init(CYBSP_EZI2C_SCL_PORT, CYBSP_EZI2C_SCL_PIN, &CYBSP_EZI2C_SCL_config);
    Cy_GPIO_Pin_Init(CYBSP_EZI2C_SDA_PORT, CYBSP_EZI2C_SDA_PIN, &CYBSP_EZI2C_SDA_config);

    /* Configure the peripheral clock for EZI2C */
    Cy_SysClk_PeriphAssignDivider(PCLK_SCB3_CLOCK, CY_SYSCLK_DIV_8_BIT, 1U);
    Cy_SysClk_PeriphDisableDivider(CY_SYSCLK_DIV_8_BIT, 1U);
    Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_8_BIT, 1U, 7U);
    Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_8_BIT, 1U);

    Cy_SCB_EZI2C_Init(CYBSP_CSD_COMM_HW, &CYBSP_CSD_COMM_config, &EZI2C_context);

    /* Initialize and enable EZI2C interrupts */
    Cy_SysInt_Init(&EZI2C_ISR_cfg, &EZI2C_InterruptHandler);
    NVIC_EnableIRQ(EZI2C_ISR_cfg.intrSrc);

    /* Set up communication data buffer to CapSense data structure to be exposed
     * to I2C master at primary slave address request.
     */
    Cy_SCB_EZI2C_SetBuffer1(CYBSP_CSD_COMM_HW, (uint8 *)&cy_capsense_tuner,
                            sizeof(cy_capsense_tuner), sizeof(cy_capsense_tuner), &EZI2C_context);

    /* Enable EZI2C block */
    Cy_SCB_EZI2C_Enable(CYBSP_CSD_COMM_HW);
}


/*******************************************************************************
* Function Name: ProcessTouchStatus
********************************************************************************
*
* Summary:
*   Controls the LED status according to the status of CapSense widgets and
*   prints the status to serial terminal.
*
*******************************************************************************/
void ProcessTouchStatus(void)
{
    uint32_t currSliderPos;
    uint32_t currBtn0Status = Cy_CapSense_IsSensorActive(CY_CAPSENSE_BUTTON0_WDGT_ID, CY_CAPSENSE_BUTTON0_SNS0_ID, &cy_capsense_context);
    uint32_t currBtn1Status = Cy_CapSense_IsSensorActive(CY_CAPSENSE_BUTTON1_WDGT_ID, CY_CAPSENSE_BUTTON1_SNS0_ID, &cy_capsense_context);
    cy_stc_capsense_touch_t *sldrTouch = Cy_CapSense_GetTouchInfo(CY_CAPSENSE_LINEARSLIDER0_WDGT_ID, &cy_capsense_context);
    char outputString[80];
    if(currBtn0Status != prevBtn0Status) {
        printf("Button_0 status: %u\r\n", currBtn0Status);
        sprintf(outputString,"  Button_0 status: %u   ", currBtn0Status);
        GUI_SetTextAlign(GUI_TA_HCENTER);
        GUI_DispStringAt(outputString, 160, 60);
        if (currBtn0Status) {
            if(btn0ToggleStatus) {
                btn0ToggleStatus = false;
                /* Turn The Blue RGB LED off */
                ledBlue2 = LED_OFF;
                 /* turn virtual Blue led off */
                GUI_SetColor(50);
                GUI_FillCircle(240,70,8);
            } else {
                btn0ToggleStatus = true;
                /* Turn The Blue RGB LED on */
                ledBlue2 = LED_ON;
                /* turn virtual led on */
                GUI_SetColor(255);
                GUI_FillCircle(240,70,8);
            }
        }
        GUI_SetColor(GUI_WHITE);

        prevBtn0Status = currBtn0Status;
    }

    if(currBtn1Status != prevBtn1Status) {
        printf("Button_1 status: %u\r\n", currBtn1Status);
        sprintf(outputString,"  Button_1 status: %u   ", currBtn1Status);
        GUI_SetTextAlign(GUI_TA_HCENTER);
        GUI_DispStringAt(outputString, 160, 80);
        btn1ToggleStatus = !btn1ToggleStatus;
        if (currBtn1Status) {
            if(btn1ToggleStatus) {
                btn1ToggleStatus = false;
                /* Turn The Red RGB LED off */
                ledRed2 = LED_OFF;
                /* turn virtual led off */
                GUI_SetColor(0x320000);
                GUI_FillCircle(240,90,8);
            } else {
                btn1ToggleStatus = true;
                /* Turn The Red RGB LED on */
                ledRed2 = LED_ON;
                /* turn virtual led on */
                GUI_SetColor(0xff0000);
                GUI_FillCircle(240,90,8);
            }
        }
        GUI_SetColor(GUI_WHITE);
        prevBtn1Status = currBtn1Status;
    }
    if(sw2Pressed != prevSw2Pressed) {
        printf("Button sw2 status: %u\r\n", sw2Pressed);
        sprintf(outputString,"  Button_2 status: %u   ", sw2Pressed);
        GUI_SetTextAlign(GUI_TA_HCENTER);
        GUI_DispStringAt(outputString, 160, 100);
        sw2ToggleStatus = !sw2ToggleStatus;
        if (sw2Pressed) {
            if(sw2ToggleStatus) {
                sw2ToggleStatus = false;
                /* Turn The Green RGB LED off */
                ledGreen2 = LED_OFF;
                /* turn virtual Green led off */
                GUI_SetColor(0x3200);
                GUI_FillCircle(240,110,8);
            } else {
                sw2ToggleStatus = true;
                /* Turn The Green RGB LED on */
                ledGreen2 = LED_ON;
                /* turn virtual Green led on */
                GUI_SetColor(0xff00);
                GUI_FillCircle(240,110,8);
            }
        }
        GUI_SetColor(GUI_WHITE);
        prevSw2Pressed = sw2Pressed;
    }
    if (sldrTouch->numPosition == SLIDER_NUM_TOUCH) {
        currSliderPos = sldrTouch->ptrPosition->x;

        if(currSliderPos != prevSliderPos) {
            printf("Slider position: %u\r\n", currSliderPos);
            sprintf(outputString,"  Slider position: %u   ", currSliderPos);
            GUI_SetTextAlign(GUI_TA_HCENTER);
            GUI_DispStringAt(outputString, 160, 120);
            myPwm.pulsewidth_ms((100-currSliderPos)/10);
            GUI_SetColor(GUI_BLACK);
            GUI_SetPenSize(10);
            GUI_DrawLine((61 + (currSliderPos * 2)), 150, 260, 150);
            GUI_SetColor(GUI_MAGENTA);
            GUI_SetPenSize(10);
            GUI_DrawLine(60, 150, (60 + (currSliderPos * 2)), 150);
            GUI_SetColor(GUI_WHITE);
            prevSliderPos = currSliderPos;
        }
    }
    /* flash a LED when a key press is detected */
    userLed = (sw2Pressed || currBtn0Status || currBtn1Status || (sldrTouch->numPosition == SLIDER_NUM_TOUCH)) ? nLED_ON : nLED_OFF;
}


/*******************************************************************************
* Function Name: EZI2C_InterruptHandler
********************************************************************************
* Summary:
*   Wrapper function for handling interrupts from EZI2C block.
*
*******************************************************************************/
void EZI2C_InterruptHandler(void)
{
    Cy_SCB_EZI2C_Interrupt(CYBSP_CSD_COMM_HW, &EZI2C_context);
}

/*****************************************************************************
* Function Name: CapSense_InterruptHandler()
******************************************************************************
* Summary:
*  Wrapper function for handling interrupts from CSD block.
*
*****************************************************************************/
void CapSense_InterruptHandler(void)
{
    Cy_CapSense_InterruptHandler(CYBSP_CSD_HW, &cy_capsense_context);
}


/*****************************************************************************
* Function Name: CapSenseEndOfScanCallback()
******************************************************************************
* Summary:
*  This function releases a semaphore to indicate end of a CapSense scan.
*
* Parameters:
*  cy_stc_active_scan_sns_t* : pointer to active sensor details.
*
*****************************************************************************/
void CapSenseEndOfScanCallback(cy_stc_active_scan_sns_t * ptrActiveScan)
{
    capsense_sem.release();
}


/*****************************************************************************
* Function Name: InitCapSenseClock()
******************************************************************************
* Summary:
*  This function configures the peripheral clock for CapSense.
*
*****************************************************************************/
void InitCapSenseClock(void)
{
    Cy_SysClk_PeriphAssignDivider(PCLK_CSD_CLOCK, CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM);
    Cy_SysClk_PeriphDisableDivider(CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM);
    Cy_SysClk_PeriphSetDivider(CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM, 0u);
    Cy_SysClk_PeriphEnableDivider(CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM);
}
void LED_Init(void)
{
    /* Turn off all LEDs */
    ledGreen = nLED_OFF;
    ledRed = nLED_OFF;
    ledBlue = nLED_OFF;
    userLed = nLED_OFF;
    ledGreen2 = LED_OFF; /* 1 for on 0 for off */
    ledRed2 = LED_OFF;
    ledBlue2 = LED_OFF;

    /* Setup pwm output initially at 50% */
    myPwm.period_ms(10);
    myPwm.pulsewidth_ms(5);

}

void Display_Init(void)
{

    /* memory buffer for sprintf */
    char outputString[80];

    /* Set font size, foreground and background Colours */
    GUI_SetFont(GUI_FONT_16B_1);
    GUI_SetColor(GUI_WHITE);
    GUI_SetBkColor(GUI_BLACK);

    /* Clear screen and print splash screen */
    GUI_Clear();
    GUI_SetTextAlign(GUI_TA_HCENTER);
    GUI_DispStringAt("Capsense Demo", 160, 20);
    printf("\r\nApplication has started. Touch any CapSense button or slider.\r\n");
    sprintf(outputString,"\r\nApplication has started.\r\n Touch any CapSense button or slider.");
    GUI_SetTextAlign(GUI_TA_HCENTER);
    GUI_DispStringAt(outputString, 160, 180);
    wait(0.10);
}

void CapSense_Init(void)
{

    /* memory buffer for sprintf */
    char outputString[80];

    /* Configure AMUX bus for CapSense */
    init_cycfg_routing();

    /* Configure PERI clocks for CapSense */
    InitCapSenseClock();

    InitTunerCommunication();

    /* Initialize the CSD HW block to the default state. */
    cy_status status = Cy_CapSense_Init(&cy_capsense_context);
    if(CY_RET_SUCCESS != status) {
        printf("CapSense initialization failed. Status code: %u\r\n", status);
        sprintf(outputString,"CapSense initialization failed. Status code: %u", status);
        GUI_SetTextAlign(GUI_TA_HCENTER);
        GUI_DispStringAt(outputString, 160, 40);
        wait(osWaitForever);
    }
    /* Initialize CapSense interrupt */
    Cy_SysInt_Init(&CapSense_ISR_cfg, &CapSense_InterruptHandler);
    NVIC_ClearPendingIRQ(CapSense_ISR_cfg.intrSrc);
    NVIC_EnableIRQ(CapSense_ISR_cfg.intrSrc);

    /* Initialize the CapSense firmware modules. */
    Cy_CapSense_Enable(&cy_capsense_context);
    Cy_CapSense_RegisterCallback(CY_CAPSENSE_END_OF_SCAN_E, CapSenseEndOfScanCallback, &cy_capsense_context);

}

/* Setup debounced mechanical buttons and callbacks*/
void Button_Init(void)
{

    /* Use internal pullups for pushbutton */
    pb2.mode(PullUp);
//    pb2.mode(PullUp);
    // Delay for initial pullup to take effect
    wait(.01);
    // Setup Interrupt callback functions for a pb hit
    pb2.attach_deasserted(&pb2_hit_callback);
//    pb2.attach_deasserted(&pb2_hit_callback);
    // Start sampling pb inputs using interrupts
    pb2.setSampleFrequency();

    pb2.attach_asserted( &pb2_released_callback );
}

/*****************************************************************************
* Function Name: main()
******************************************************************************
* Summary:
*   Main function that starts a thread for CapSense scan, initialises the
*   tft screen, debounce buttons, turns off LEDs and enters a forever
*   wait state.
*
*****************************************************************************/
int main(void)
{

    /* Initialise EmWin driver*/
    GUI_Init();

    /* Initialise display */
    Display_Init();

    /* Set up CapSense paramteters */
    CapSense_Init();

    /* Create a thread to run CapSense scan periodically using an event queue
     * dispatcher.
     */
    Thread thread(osPriorityNormal, OS_STACK_SIZE, NULL, "CapSense Scan Thread");
    thread.start(callback(&queue, &EventQueue::dispatch_forever));
    queue.call_every(CAPSENSE_SCAN_PERIOD_MS, RunCapSenseScan);

    /* Initiate scan immediately since the first call of RunCapSenseScan()
     * happens CAPSENSE_SCAN_PERIOD_MS after the event queue dispatcher has
     * started.
     */
    Cy_CapSense_ScanAllWidgets(&cy_capsense_context);

    /* Setup debounced mechanical buttons and callbacks*/
    Button_Init();

    /* Turn off all LEDs, set up pwm drive */
    LED_Init();

    /* everything is started so goto sleep forever while events control the hardware */
    wait(osWaitForever);

}