From f7cd9b461ca33845339f4a11f49bdc142696827a Mon Sep 17 00:00:00 2001 From: Dominik Sliwa Date: Tue, 28 Jun 2016 09:51:29 +0200 Subject: Apalis_TK1_K20: SPI Communication, ADC, TSC, GPIO Support for Communication between TK1 SoC and K20 MCU This patch includes ADC, TSC and GPIO functionality. Signed-off-by: Dominik Sliwa --- source/adc_task.c | 343 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ source/adc_task.h | 19 +++ source/com_task.c | 205 ++++++++++++++++++++++++++++++++ source/com_task.h | 130 +++++++++++++++++++++ source/gpio_ext.c | 141 ++++++++++++++++++++++ source/gpio_ext.h | 73 ++++++++++++ source/main.c | 83 +++++++++---- 7 files changed, 973 insertions(+), 21 deletions(-) create mode 100644 source/adc_task.c create mode 100644 source/adc_task.h create mode 100644 source/com_task.c create mode 100644 source/com_task.h create mode 100644 source/gpio_ext.c create mode 100644 source/gpio_ext.h (limited to 'source') diff --git a/source/adc_task.c b/source/adc_task.c new file mode 100644 index 0000000..67d5bd0 --- /dev/null +++ b/source/adc_task.c @@ -0,0 +1,343 @@ +/* + * adc_task.c + * + */ + +#include "com_task.h" +#include "adc_task.h" +#include "fsl_adc16.h" +#include "fsl_port.h" +#include "errno.h" +#include "stdlib.h" + +/* + * Apalis ADC0 -> PTB0 -> ADC0_SE8 + * Apalis ADC1 -> PTB1 -> ADC0_SE9 + * Apalis ADC2 -> PTB2 -> ADC0_SE12 + * Apalis ADC3 -> PTB3 -> ADC0_SE13 + * + * Touch screen: + * Force: + * PTE6 X+ hi-off + * PTB9 X- lo-off + * PTC5 Y+ hi-off + * PTC13 Y- lo-off + * Sense: + * PTB7 -> ADC1_SE13 X- + * PTB6 -> ADC1_SE12 X+ + * PTC9 -> ADC1_SE5b Y- + * PTC8 -> ADC1_SE4b Y+ + */ +const uint8_t adc0_channels[ADC0_CHANNEL_CNT] = {8, 9, 12, 13}; +const uint8_t tsc_channels[TSC0_CHANNEL_CNT] = {13, 12, 5, 4}; + +static int adc_task_init(void) +{ + adc16_config_t adc_config; +#ifdef BOARD_USES_ADC + ADC16_GetDefaultConfig(&adc_config); + adc_config.resolution = kADC16_ResolutionSE16Bit; + adc_config.longSampleMode = kADC16_LongSampleDisabled; + adc_config.clockDivider = kADC16_ClockDivider8; + ADC16_Init(ADC0, &adc_config); + ADC16_SetHardwareAverage(ADC0, kADC16_HardwareAverageDisabled); + return 0; +#else + return -ENODEV; +#endif +} + +static int tsc_task_init(void) +{ + adc16_config_t adc_config; +#ifdef BOARD_USES_ADC + ADC16_GetDefaultConfig(&adc_config); + adc_config.resolution = kADC16_ResolutionSE12Bit; + adc_config.longSampleMode = kADC16_LongSampleDisabled; + adc_config.clockDivider = kADC16_ClockDivider8; + ADC16_Init(ADC1, &adc_config); + ADC16_SetChannelMuxMode(ADC1, kADC16_ChannelMuxB); + ADC16_SetHardwareAverage(ADC1, kADC16_HardwareAverageCount32); + return 0; +#else + return -ENODEV; +#endif +} + +#ifdef BOARD_USES_ADC +static void ts_force_drive(uint8_t xm, uint8_t xp, uint8_t ym, uint8_t yp) +{ + if (xp == 0) + GPIO_SetPinsOutput(GPIOE, 1 << 6); + else + GPIO_ClearPinsOutput(GPIOE, 1 << 6); + + if (xm > 0) + GPIO_SetPinsOutput(GPIOB, 1 << 9); + else + GPIO_ClearPinsOutput(GPIOB, 1 << 9); + + if (yp == 0) + GPIO_SetPinsOutput(GPIOC, 1 << 5); + else + GPIO_ClearPinsOutput(GPIOC, 1 << 5); + + if (ym > 0) + GPIO_SetPinsOutput(GPIOC, 1 << 13); + else + GPIO_ClearPinsOutput(GPIOC, 1 << 13); +} + +static inline uint16_t do_adc_conversion(ADC_Type *base, adc16_channel_config_t *channel) +{ + ADC16_SetChannelConfig(base, 0, channel); + while(ADC16_GetChannelStatusFlags(base, 0) == 0){vTaskDelay(0);} + return (uint16_t)ADC16_GetChannelConversionValue(base, 0); +} + +void adc_task(void *pvParameters) +{ + adc16_channel_config_t channel; + int i; + if (adc_task_init() < 0) + return; + + channel.enableDifferentialConversion = false; + channel.enableInterruptOnConversionCompleted = false; + + while(1) { + for (i = 0; i < ADC0_CHANNEL_CNT;i ++){ + channel.channelNumber = adc0_channels[i]; + gen_regs.adc[i] = do_adc_conversion(ADC0, &channel); + } + vTaskDelay(1); + } + +} + +enum touch_status { + PEN_UP, + PEN_DOWN +}; + +#define MIN_TOUCH_DET 5 + +/* PTB7 -> ADC1_SE13 X- + * PTB6 -> ADC1_SE12 X+ + * PTC9 -> ADC1_SE5b Y- + * PTC8 -> ADC1_SE4b Y+ + */ +void tsc_task(void *pvParameters) +{ + adc16_channel_config_t channel; + port_pin_config_t pin_config_pd, pin_config_ana; + int old_status, status = PEN_UP; + int irq_stat = 0; + if (tsc_task_init() < 0) + return; + + pin_config_pd.mux = kPORT_MuxAsGpio; + pin_config_pd.openDrainEnable = kPORT_OpenDrainDisable; + pin_config_pd.pullSelect = kPORT_PullDown; + pin_config_pd.slewRate = kPORT_FastSlewRate; + pin_config_pd.passiveFilterEnable = kPORT_PassiveFilterDisable; + pin_config_pd.driveStrength = kPORT_LowDriveStrength; + pin_config_pd.lockRegister = kPORT_UnlockRegister; + + pin_config_ana.mux = kPORT_PinDisabledOrAnalog; + pin_config_ana.openDrainEnable = kPORT_OpenDrainDisable; + pin_config_ana.pullSelect = kPORT_PullDisable; + pin_config_ana.slewRate = kPORT_FastSlewRate; + pin_config_ana.passiveFilterEnable = kPORT_PassiveFilterDisable; + pin_config_ana.driveStrength = kPORT_LowDriveStrength; + pin_config_ana.lockRegister = kPORT_UnlockRegister; + + channel.enableDifferentialConversion = false; + channel.enableInterruptOnConversionCompleted = false; + + while(1) { + //Touch detect power Y+, enable pulldown on xp and read xp GPIO + ts_force_drive(0, 0, 0, 1); + PORT_SetPinConfig(PORTB, 6u, &pin_config_pd); + vTaskDelay(10); + old_status = status; + status = GPIO_ReadPinInput(GPIOB, 6u) ? PEN_DOWN:PEN_UP; + PORT_SetPinConfig(PORTB, 6u, &pin_config_ana); + + if (status != old_status) + irq_stat = 0; + + if (status == PEN_DOWN) { + //probe ym with power across Y plane + ts_force_drive(0, 0, 1, 1); + vTaskDelay(10); + channel.channelNumber = tsc_channels[0]; + gen_regs.tsc_ym = do_adc_conversion(ADC1, &channel); + + //probe yp with power across Y plane + channel.channelNumber = tsc_channels[1]; + gen_regs.tsc_yp = do_adc_conversion(ADC1, &channel); + + //probe xm with power across X plane + ts_force_drive(1, 1, 0, 0); + vTaskDelay(10); + channel.channelNumber = tsc_channels[2]; + gen_regs.tsc_xm = do_adc_conversion(ADC1, &channel); + + //probe xp with power across X plane + channel.channelNumber = tsc_channels[3]; + gen_regs.tsc_xp = do_adc_conversion(ADC1, &channel); + + if (irq_stat == 0) { + generate_irq(APALIS_TK1_K20_TSC_IRQ); + irq_stat = 1; + } + } else { + gen_regs.tsc_xm = 0; + gen_regs.tsc_xp = 0; + gen_regs.tsc_ym = 0; + gen_regs.tsc_yp = 0; + vTaskDelay(20); + if (irq_stat == 0) { + generate_irq(APALIS_TK1_K20_TSC_IRQ); + irq_stat = 1; + } + } + vTaskDelay(10); + } + +} + +int tsc_registers(uint8_t *rx_buf, uint8_t *tx_buf) +{ + if (rx_buf[0] == APALIS_TK1_K20_READ_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_TSCREG: + tx_buf[0] = 0x00; + return 1; + case APALIS_TK1_K20_TSC_XML: + tx_buf[0] = gen_regs.tsc_xm & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_XMH: + tx_buf[0] = (gen_regs.tsc_xm >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_XPL: + tx_buf[0] = gen_regs.tsc_xp & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_XPH: + tx_buf[0] = (gen_regs.tsc_xp >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_YML: + tx_buf[0] = gen_regs.tsc_ym & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_YMH: + tx_buf[0] = (gen_regs.tsc_ym >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_YPL: + tx_buf[0] = gen_regs.tsc_yp & 0xFF; + return 1; + case APALIS_TK1_K20_TSC_YPH: + tx_buf[0] = (gen_regs.tsc_yp >> 8) & 0xFF; + return 1; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_WRITE_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_TSCREG: + return -ENOENT; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_BULK_READ_INST) { + switch (rx_buf[1]){ + case APALIS_TK1_K20_TSC_XML: + tx_buf[0] = gen_regs.tsc_xm & 0xFF; + tx_buf[1] = (gen_regs.tsc_xm >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_TSC_XPL: + tx_buf[0] = gen_regs.tsc_xp & 0xFF; + tx_buf[1] = (gen_regs.tsc_xp >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_TSC_YML: + tx_buf[0] = gen_regs.tsc_ym & 0xFF; + tx_buf[1] = (gen_regs.tsc_ym >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_TSC_YPL: + tx_buf[0] = gen_regs.tsc_yp & 0xFF; + tx_buf[1] = (gen_regs.tsc_yp >> 8) & 0xFF; + return 2; + default: + return -ENOENT; + } + } + return -ENOENT; +} + +int adc_registers(uint8_t *rx_buf, uint8_t *tx_buf) +{ + if (rx_buf[0] == APALIS_TK1_K20_READ_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_ADCREG: + tx_buf[0] = 0x00; + return 1; + case APALIS_TK1_K20_ADC_CH0L: + tx_buf[0] = gen_regs.adc[0] & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH0H: + tx_buf[0] = (gen_regs.adc[0] >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH1L: + tx_buf[0] = gen_regs.adc[1] & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH1H: + tx_buf[0] = (gen_regs.adc[1] >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH2L: + tx_buf[0] = gen_regs.adc[2] & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH2H: + tx_buf[0] = (gen_regs.adc[2] >> 8) & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH3L: + tx_buf[0] = gen_regs.adc[3] & 0xFF; + return 1; + case APALIS_TK1_K20_ADC_CH3H: + tx_buf[0] = (gen_regs.adc[3] >> 8) & 0xFF; + return 1; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_WRITE_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_ADCREG: + return -ENOENT; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_BULK_READ_INST) { + switch (rx_buf[1]){ + case APALIS_TK1_K20_ADC_CH0L: + tx_buf[0] = gen_regs.adc[0] & 0xFF; + tx_buf[1] = (gen_regs.adc[0] >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_ADC_CH1L: + tx_buf[0] = gen_regs.adc[1] & 0xFF; + tx_buf[1] = (gen_regs.adc[1] >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_ADC_CH2L: + tx_buf[0] = gen_regs.adc[2] & 0xFF; + tx_buf[1] = (gen_regs.adc[2] >> 8) & 0xFF; + return 2; + case APALIS_TK1_K20_ADC_CH3L: + tx_buf[0] = gen_regs.adc[3] & 0xFF; + tx_buf[1] = (gen_regs.adc[3] >> 8) & 0xFF; + return 2; + + default: + return -ENOENT; + } + } + return -ENOENT; +} +#endif diff --git a/source/adc_task.h b/source/adc_task.h new file mode 100644 index 0000000..3dafddb --- /dev/null +++ b/source/adc_task.h @@ -0,0 +1,19 @@ +/* + * adc_task.h + * + */ + +#ifndef SOURCE_ADC_TASK_H_ +#define SOURCE_ADC_TASK_H_ +#include "board.h" + +#ifdef BOARD_USES_ADC +TaskHandle_t adc_task_handle; +TaskHandle_t tsc_task_handle; +void adc_task(void *pvParameters); +void tsc_task(void *pvParameters); +int adc_registers(uint8_t *rx_buf, uint8_t *tx_buf); +int tsc_registers(uint8_t *rx_buf, uint8_t *tx_buf); +#endif + +#endif /* SOURCE_ADC_TASK_H_ */ diff --git a/source/com_task.c b/source/com_task.c new file mode 100644 index 0000000..348c3e1 --- /dev/null +++ b/source/com_task.c @@ -0,0 +1,205 @@ + +#include "com_task.h" +#include "gpio_ext.h" +#include "adc_task.h" + +/* Put FW version at known address in binary. Make it 32-bit to have room for the future*/ +const uint32_t __attribute__((section(".FwVersion"))) fw_version = APALIS_TK1_K20_FW_VER; + +#define MAX_TRANSFER_SIZE 32U +static dspi_slave_handle_t spi_handle; +static uint8_t slaveRxData[MAX_TRANSFER_SIZE] = {0U}; +static uint8_t slaveTxData[MAX_TRANSFER_SIZE] = {0U}; + +void generate_irq(uint8_t irq) { + gen_regs.irq = gen_regs.irq | BIT(irq); + /* Toggle INT1 pin */ + GPIO_TogglePinsOutput(GPIOA, 1u << 16u); +} + +void clear_irq_flag(uint8_t irq) { + gen_regs.irq = ~irq & gen_regs.irq; +} + +uint8_t get_control_reg() +{ + return gen_regs.control; + +} + +void set_control_reg(uint8_t value) +{ + gen_regs.control = value; +} + +uint8_t get_status_reg() +{ + return gen_regs.status; + +} + +void set_status_reg(uint8_t value) +{ + gen_regs.status = value; +} + +uint8_t get_mask_reg() +{ + return gen_regs.irq_mask; + +} + +void set_mask_reg(uint8_t value) +{ + gen_regs.irq_mask = value; +} + +uint8_t get_irq_reg() +{ + return gen_regs.irq; + +} + +void set_irq_reg(uint8_t value) +{ + /* Clear IRQ flag on 1 */ + clear_irq_flag(value); + +} + +int inline general_registers(uint8_t *rx_buf, uint8_t * tx_buf) { + + if (rx_buf[0] == APALIS_TK1_K20_READ_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_STAREG: + tx_buf[0] = get_status_reg(); + return 1; + case APALIS_TK1_K20_REVREG: + tx_buf[0] = APALIS_TK1_K20_FW_VER; + return 1; + case APALIS_TK1_K20_IRQREG: + tx_buf[0] = get_irq_reg(); + return 1; + case APALIS_TK1_K20_CTRREG: + tx_buf[0] = get_control_reg(); + return 1; + case APALIS_TK1_K20_MSQREG: + tx_buf[0] = get_mask_reg(); + return 1; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_WRITE_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_STAREG: + set_status_reg(rx_buf[2]); + return 0; + case APALIS_TK1_K20_REVREG: + return -ENOENT; + case APALIS_TK1_K20_IRQREG: + set_irq_reg(rx_buf[2]); + return 0; + case APALIS_TK1_K20_CTRREG: + set_control_reg(rx_buf[2]); + return 0; + case APALIS_TK1_K20_MSQREG: + set_mask_reg(rx_buf[2]); + return 0; + default: + return -ENOENT; + } + } + + + return -ENOENT; +} + +static void SPI_callback(SPI_Type *base, dspi_slave_handle_t *handle, status_t status, void *userData) +{ + callback_message_t * cb = (callback_message_t*) userData; + BaseType_t reschedule = pdFALSE; + + if (status == kStatus_Success) + { + xSemaphoreGiveFromISR(cb->sem, &reschedule); + } + + if (status == kStatus_DSPI_Error) + { + __NOP(); + } + portYIELD_FROM_ISR(reschedule); +} + +static void SPI_init() { + dspi_slave_config_t slaveConfig; + /* Slave config */ + slaveConfig.whichCtar = kDSPI_Ctar0; + slaveConfig.ctarConfig.bitsPerFrame = 8; + slaveConfig.ctarConfig.cpol = kDSPI_ClockPolarityActiveHigh; + slaveConfig.ctarConfig.cpha = kDSPI_ClockPhaseSecondEdge; + slaveConfig.enableContinuousSCK = true; + slaveConfig.enableRxFifoOverWrite = false; + slaveConfig.enableModifiedTimingFormat = false; + slaveConfig.samplePoint = kDSPI_SckToSin0Clock; + + DSPI_SlaveInit(SPI2, &slaveConfig); + DSPI_SlaveTransferCreateHandle(SPI2, &spi_handle, SPI_callback, spi_handle.userData); + + /* Set dspi slave interrupt priority higher. */ + NVIC_SetPriority(SPI2_IRQn, 5U); + GPIO_ClearPinsOutput(GPIOA, 1u << 29u); /* INT2 active */ + PRINTF("SPI init done \r\n"); + +} + +void spi_task(void *pvParameters) { + callback_message_t cb_msg; + dspi_transfer_t slaveXfer; + int ret; + + cb_msg.sem = xSemaphoreCreateBinary(); + spi_handle.userData = &cb_msg; + SPI_init(); + GPIO_SetPinsOutput(GPIOA, 1u << 29u); /* INT2 idle */ + + while(1){ + slaveXfer.txData = slaveTxData; + slaveXfer.rxData = slaveRxData; + slaveXfer.dataSize = 3; + slaveXfer.configFlags = kDSPI_SlaveCtar0; + /* Wait for instructions from SoC */ + DSPI_SlaveTransferNonBlocking(SPI2, &spi_handle, &slaveXfer); + xSemaphoreTake(cb_msg.sem, portMAX_DELAY); + if (slaveRxData[1] <= 0x05) { + ret = general_registers(slaveRxData, &slaveTxData[1]); +#ifdef BOARD_USES_ADC + } else if ((slaveRxData[1] >= APALIS_TK1_K20_ADCREG) && (slaveRxData[1] <= APALIS_TK1_K20_ADC_CH3H)) { + ret = adc_registers(slaveRxData, &slaveTxData[1]); + + } else if ((slaveRxData[1] >= APALIS_TK1_K20_TSCREG) && (slaveRxData[1] <= APALIS_TK1_K20_TSC_YPH)) { + ret = tsc_registers(slaveRxData, &slaveTxData[1]); +#endif + } else if ((slaveRxData[1] >= APALIS_TK1_K20_GPIOREG) && (slaveRxData[1] <= APALIS_TK1_K20_GPIO_STA)) { + ret = gpio_registers(slaveRxData, &slaveTxData[1]); + + } else { + /* Register not defined */ + ret = -EINVAL; + } + + if (ret < 0) { + slaveTxData[0] = TK1_K20_INVAL; + slaveTxData[1] = TK1_K20_INVAL; + } else { + slaveTxData[0] = TK1_K20_SENTINEL; + } + + if (slaveRxData[0] == APALIS_TK1_K20_READ_INST || slaveRxData[0] == APALIS_TK1_K20_BULK_READ_INST) + { + slaveXfer.dataSize = (ret >= 0) ? (ret + 1):2; /* Extra byte is for sentinel */ + DSPI_SlaveTransferNonBlocking(SPI2, &spi_handle, &slaveXfer); + xSemaphoreTake(cb_msg.sem, portMAX_DELAY); + } + } +} diff --git a/source/com_task.h b/source/com_task.h new file mode 100644 index 0000000..14c742e --- /dev/null +++ b/source/com_task.h @@ -0,0 +1,130 @@ +/* + * com_task.h + */ + +#ifndef COM_TASK_H_ +#define COM_TASK_H_ + +#include "board.h" +#include "fsl_debug_console.h" +#include "fsl_dspi.h" +#include "fsl_gpio.h" + +/* FreeRTOS kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "timers.h" +#include "semphr.h" +#include "errno.h" + +typedef struct _callback_message_t +{ + status_t async_status; + SemaphoreHandle_t sem; +} callback_message_t; + +TaskHandle_t spi_task_handle; +void generate_irq(uint8_t irq); +void clear_irq_flag(uint8_t irq); +void spi_task(void *pvParameters); + +#define BIT(nr) (1UL << (nr)) + + +/* Commands and registers used in SPI communication */ + +/* Commands*/ +#define APALIS_TK1_K20_READ_INST 0x0F +#define APALIS_TK1_K20_WRITE_INST 0xF0 +#define APALIS_TK1_K20_BULK_WRITE_INST 0x3C +#define APALIS_TK1_K20_BULK_READ_INST 0xC3 + +#define APALIS_TK1_K20_MAX_BULK (64) + +/* General registers*/ +#define APALIS_TK1_K20_STAREG 0x00 /* General status register RO */ +#define APALIS_TK1_K20_REVREG 0x01 /* FW revision register RO*/ +#define APALIS_TK1_K20_IRQREG 0x02 /* IRQ status RW(write of 1 will reset the bit) */ +#define APALIS_TK1_K20_CTRREG 0x03 /* General control register RW */ +#define APALIS_TK1_K20_MSQREG 0x04 /* IRQ mask register RW */ + +/* CAN Registers */ +#define APALIS_TK1_K20_CANREG 0x10 /* CAN control & status register RW */ +#define APALIS_TK1_K20_CAN_BAUD_REG 0x11 /* CAN Baud set register RW */ +#define APALIS_TK1_K20_CAN_IN_BUF_CNT 0x12 /* CAN IN BUF Received Data Count RO */ +#define APALIS_TK1_K20_CAN_IN_BUF 0x13 /* CAN IN BUF RO */ +#define APALIS_TK1_K20_CAN_OUT_BUF_CNT 0x14 /* CAN OUT BUF Data Count WO, must be written before bulk write to APALIS_TK1_K20_CAN0_OUT_BUF_CNT */ +#define APALIS_TK1_K20_CAN_OUT_FIF0 0x15 /* CAN OUT BUF WO */ + +#define APALIS_TK1_K20_CAN_DEV_OFFSET(x) (x ? 0:0x10) + +/* ADC Registers */ +#define APALIS_TK1_K20_ADCREG 0x30 /* ADC control & status register RW */ +#define APALIS_TK1_K20_ADC_CH0L 0x31 /* ADC Channel 0 LSB RO */ +#define APALIS_TK1_K20_ADC_CH0H 0x32 /* ADC Channel 0 MSB RO */ +#define APALIS_TK1_K20_ADC_CH1L 0x33 /* ADC Channel 1 LSB RO */ +#define APALIS_TK1_K20_ADC_CH1H 0x34 /* ADC Channel 1 MSB RO */ +#define APALIS_TK1_K20_ADC_CH2L 0x35 /* ADC Channel 2 LSB RO */ +#define APALIS_TK1_K20_ADC_CH2H 0x36 /* ADC Channel 2 MSB RO */ +#define APALIS_TK1_K20_ADC_CH3L 0x37 /* ADC Channel 3 LSB RO */ +#define APALIS_TK1_K20_ADC_CH3H 0x38 /* ADC Channel 3 MSB RO */ +/* Bulk read of LSB register can be use to read entire 16-bit in one command */ + +/* TSC Register */ +#define APALIS_TK1_K20_TSCREG 0x40 /* TSC control & status register RW */ +#define APALIS_TK1_K20_TSC_XML 0x41 /* TSC X- data LSB RO */ +#define APALIS_TK1_K20_TSC_XMH 0x42 /* TSC X- data MSB RO */ +#define APALIS_TK1_K20_TSC_XPL 0x43 /* TSC X+ data LSB RO */ +#define APALIS_TK1_K20_TSC_XPH 0x44 /* TSC X+ data MSB RO */ +#define APALIS_TK1_K20_TSC_YML 0x45 /* TSC Y- data LSB RO */ +#define APALIS_TK1_K20_TSC_YMH 0x46 /* TSC Y- data MSB RO */ +#define APALIS_TK1_K20_TSC_YPL 0x47 /* TSC Y+ data LSB RO */ +#define APALIS_TK1_K20_TSC_YPH 0x48 /* TSC Y+ data MSB RO */ +/* Bulk read of LSB register can be use to read entire 16-bit in one command */ +#define APALIS_TK1_K20_TSC_ENA BIT(0) +#define APALIS_TK1_K20_TSC_ENA_MASK 0xFE + +/* GPIO Registers */ +#define APALIS_TK1_K20_GPIOREG 0x50 /* GPIO control & status register RW */ +#define APALIS_TK1_K20_GPIO_NO 0x51 /* currently configured GPIO RW */ +#define APALIS_TK1_K20_GPIO_STA 0x52 /* Status register for the APALIS_TK1_K20_GPIO_NO GPIO RW */ +/* MSB | 0 ... 0 | VALUE | Output-1 / Input-0 | LSB */ +#define APALIS_TK1_K20_GPIO_STA_OE BIT(0) +#define APALIS_TK1_K20_GPIO_STA_VAL BIT(1) + +/* Interrupt flags */ +#define APALIS_TK1_K20_GEN_IRQ 0 +#define APALIS_TK1_K20_CAN0_IRQ 1 +#define APALIS_TK1_K20_CAN1_IRQ 2 +#define APALIS_TK1_K20_ADC_IRQ 3 +#define APALIS_TK1_K20_TSC_IRQ 4 +#define APALIS_TK1_K20_GPIO_IRQ 5 + +#define APALIS_TK1_K20_FW_VER 0x05 + +#define FW_MINOR (APALIS_TK1_K20_FW_VER & 0x0F) +#define FW_MAJOR ((APALIS_TK1_K20_FW_VER & 0xF0) >> 8) + +#define TK1_K20_SENTINEL 0x55 +#define TK1_K20_INVAL 0xAA + +#define ADC0_CHANNEL_CNT 4 + +#define TSC0_CHANNEL_CNT 4 + +/* Structure with general registers */ +struct register_struct { + uint8_t status; + uint8_t control; + uint8_t irq_mask; + uint8_t irq; + uint8_t gpio_no; + uint16_t adc[ADC0_CHANNEL_CNT]; + uint16_t tsc_xm; + uint16_t tsc_xp; + uint16_t tsc_ym; + uint16_t tsc_yp; +} gen_regs; + +#endif /* COM_TASK_H_ */ diff --git a/source/gpio_ext.c b/source/gpio_ext.c new file mode 100644 index 0000000..5741cb5 --- /dev/null +++ b/source/gpio_ext.c @@ -0,0 +1,141 @@ +/* + * gpio_ext.c + * + */ + +#include "gpio_ext.h" +#include "com_task.h" +#include "errno.h" + + +static inline int port_type_to_int(PORT_Type *port) +{ + switch ((int) port) { + case PORTA_BASE: + return 0; + case PORTB_BASE: + return 1; + case PORTC_BASE: + return 2; + case PORTD_BASE: + return 3; + case PORTE_BASE: + return 4; + default: + return -EINVAL; + } +} + +/* returns GPIO index in gpio_list table and -EINVAL + * if there is no entry for this gpio. + */ +int is_gpio_valid(uint8_t pin) +{ + uint16_t i; + int temp; + if (pin == 0xFF) + return -EINVAL; + + for (i = 0; i < sizeof(gpio_list)/sizeof(struct gpio_id); i++){ + temp = port_type_to_int(gpio_list[i].port) * 32; + temp += gpio_list[i].pin; + if ( temp == pin ) + return i; + } + + return -EINVAL; +} + +int set_gpio_status(uint8_t status, uint8_t pin) +{ + gpio_pin_config_t gpio_config; + int index; + + gpio_config.pinDirection = (status & APALIS_TK1_K20_GPIO_STA_OE) ? kGPIO_DigitalOutput : kGPIO_DigitalInput; + gpio_config.outputLogic = (status & APALIS_TK1_K20_GPIO_STA_VAL); + + index = is_gpio_valid(pin); + + if (index >= 0) + GPIO_PinInit(gpio_list[index].gpio, gpio_list[index].pin, &gpio_config); + else + return index; + + return 0; +} + + +uint8_t get_gpio_status(uint8_t pin) +{ + uint8_t status; + int index; + GPIO_Type *base; + uint32_t gpio_pin; + + index = is_gpio_valid(pin); + if (index == -EINVAL) + return 0xFF; + base = gpio_list[index].gpio; + gpio_pin = gpio_list[index].pin; + + if (((base->PDDR) >> gpio_pin) & 0x01U) { + status = APALIS_TK1_K20_GPIO_STA_OE; + status += (((base->PDOR) >> gpio_pin) & 0x01U) ? APALIS_TK1_K20_GPIO_STA_VAL : 0x00; + } else { + status = 0x00; + status += (((base->PDIR) >> gpio_pin) & 0x01U) ? APALIS_TK1_K20_GPIO_STA_VAL : 0x00; + } + + return status; +} + +int gpio_registers(uint8_t *rx_buf, uint8_t *tx_buf){ + if (rx_buf[0] == APALIS_TK1_K20_READ_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_GPIOREG: + return -ENOENT; + break; + case APALIS_TK1_K20_GPIO_NO: + if (gen_regs.gpio_no != 0xFF){ + tx_buf[0] = gen_regs.gpio_no; + return 1; + } else + return -ENOENT; + break; + case APALIS_TK1_K20_GPIO_STA: + if (gen_regs.gpio_no != 0xFF){ + tx_buf[0] = get_gpio_status(gen_regs.gpio_no); + return 1; + } else + return -ENOENT; + break; + default: + return -ENOENT; + } + } else if (rx_buf[0] == APALIS_TK1_K20_WRITE_INST) { + switch (rx_buf[1]) { + case APALIS_TK1_K20_GPIOREG: + return -ENOENT; + break; + case APALIS_TK1_K20_GPIO_NO: + if (is_gpio_valid(rx_buf[2]) >= 0){ + gen_regs.gpio_no = rx_buf[2]; + return 0; + } else { + gen_regs.gpio_no = 0xFF; + return -ENOENT; + } + break; + case APALIS_TK1_K20_GPIO_STA: + return set_gpio_status(rx_buf[2], gen_regs.gpio_no); + break; + default: + return -ENOENT; + } + } + return -ENOENT; +} + + + + diff --git a/source/gpio_ext.h b/source/gpio_ext.h new file mode 100644 index 0000000..5edbf3a --- /dev/null +++ b/source/gpio_ext.h @@ -0,0 +1,73 @@ +/* + * gpio_ext.h + * + */ + +#ifndef SOURCE_GPIO_EXT_H_ +#define SOURCE_GPIO_EXT_H_ + +#include "fsl_device_registers.h" +#include "fsl_debug_console.h" +#include "board.h" + +struct gpio_id{ + PORT_Type *port; + GPIO_Type *gpio; + uint32_t pin; +}; + +struct gpio_id gpio_list [] = { + {PORTA, GPIOA, 3}, + {PORTA, GPIOA, 5}, + {PORTA, GPIOA, 17}, +#ifndef BOARD_USES_ADC + {PORTB, GPIOB, 1}, + {PORTB, GPIOB, 2}, + {PORTB, GPIOB, 3}, +#endif +#ifndef SDK_DEBUGCONSOLE + {PORTB, GPIOB, 10}, + {PORTB, GPIOB, 11}, +#endif + {PORTB, GPIOB, 16}, + {PORTB, GPIOB, 17}, + {PORTB, GPIOB, 18}, + {PORTB, GPIOB, 19}, + {PORTC, GPIOC, 0}, + {PORTC, GPIOC, 1}, + {PORTC, GPIOC, 2}, + {PORTC, GPIOC, 3}, + {PORTC, GPIOC, 4}, + {PORTC, GPIOC, 6}, + {PORTC, GPIOC, 7}, + {PORTD, GPIOD, 0}, + {PORTD, GPIOD, 1}, + {PORTD, GPIOD, 2}, + {PORTD, GPIOD, 3}, + {PORTD, GPIOD, 4}, + {PORTD, GPIOD, 5}, + {PORTD, GPIOD, 6}, + {PORTD, GPIOD, 7}, + {PORTD, GPIOD, 8}, + {PORTD, GPIOD, 9}, + {PORTD, GPIOD, 11}, + {PORTD, GPIOD, 12}, + {PORTD, GPIOD, 13}, + {PORTD, GPIOD, 14}, + {PORTD, GPIOD, 15}, + {PORTE, GPIOE, 0}, + {PORTE, GPIOE, 1}, + {PORTE, GPIOE, 2}, + {PORTE, GPIOE, 3}, + {PORTE, GPIOE, 4}, + {PORTE, GPIOE, 5}, + {PORTE, GPIOE, 24}, + {PORTE, GPIOE, 25} +}; + +int is_gpio_valid(uint8_t pin); +int set_gpio_status(uint8_t status, uint8_t pin); +uint8_t get_gpio_status(uint8_t pin); +int gpio_registers(uint8_t *rx_buf, uint8_t *tx_buf); + +#endif /* SOURCE_GPIO_EXT_H_ */ diff --git a/source/main.c b/source/main.c index 094da3a..e035d4e 100644 --- a/source/main.c +++ b/source/main.c @@ -37,7 +37,9 @@ #include "board.h" #include "pin_mux.h" #include "clock_config.h" -/*#include "fsl_debug_console.h"*/ +#include "fsl_debug_console.h" +#include "com_task.h" +#include "adc_task.h" /* FreeRTOS kernel includes. */ #include "FreeRTOS.h" @@ -46,38 +48,77 @@ #include "timers.h" +#if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) +#define CONTROLLER_ID kUSB_ControllerKhci0 +#endif +#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) +#define CONTROLLER_ID kUSB_ControllerEhci0 +#endif + /* Task priorities. */ -#define hello_task_PRIORITY (configMAX_PRIORITIES - 1) +#define debug_task_PRIORITY 1 +#define USB_HOST_INTERRUPT_PRIORITY (5U) + +/* Task handles */ + +TaskHandle_t usb_task_handle; +#ifdef SDK_DEBUGCONSOLE +TaskHandle_t debug_task_handle; +#endif + /*! - * @brief Task responsible for printing of "Hello world." message. + * @brief Debug task */ -static void hello_task(void *pvParameters) { - for (;;) { - /*PRINTF("Hello world.\r\n");*/ - /* Add your code here */ - vTaskSuspend(NULL); - } +#ifdef SDK_DEBUGCONSOLE +static void debug_task(void *pvParameters) { + for (;;) { + vTaskDelay(10000); + } } - +#endif /*! * @brief Application entry point. */ int main(void) { - /* Init board hardware. */ - BOARD_InitPins(); - BOARD_BootClockRUN(); - BOARD_InitDebugConsole(); - /* Add your code here */ + /* Init board hardware. */ + BOARD_InitPins(); + BOARD_BootClockRUN(); + BOARD_InitDebugConsole(); + PRINTF("Apalis K20 Firmware Version %d.%d\r\n", FW_MAJOR, FW_MINOR); + + /* Create RTOS task */ + if(xTaskCreate(spi_task, "SPI_task", 2000L / sizeof(portSTACK_TYPE), NULL, 4, &spi_task_handle) != pdPASS) + { + PRINTF("create SPI task error\r\n"); + } + +#ifdef BOARD_USES_ADC + if(xTaskCreate(adc_task, "ADC_task", 2000L / sizeof(portSTACK_TYPE), NULL, 2, &adc_task_handle) != pdPASS) + { + PRINTF("create ADC task error\r\n"); + } + + if(xTaskCreate(tsc_task, "TSC_task", 2000L / sizeof(portSTACK_TYPE), NULL, 2, &tsc_task_handle) != pdPASS) + { + PRINTF("create TSC task error\r\n"); + } +#endif + +#ifdef SDK_DEBUGCONSOLE + if(xTaskCreate(debug_task, "Debug_task", configMINIMAL_STACK_SIZE, NULL, debug_task_PRIORITY, &debug_task_handle) != pdPASS) + { + PRINTF("create hello task error\r\n"); + } +#endif - /* Create RTOS task */ - xTaskCreate(hello_task, "Hello_task", configMINIMAL_STACK_SIZE, NULL, hello_task_PRIORITY, NULL); - vTaskStartScheduler(); + NVIC_SetPriorityGrouping( 0 ); + vTaskStartScheduler(); - for(;;) { /* Infinite loop to avoid leaving the main function */ - __asm("NOP"); /* something to use as a breakpoint stop while looping */ - } + for(;;) { /* Infinite loop to avoid leaving the main function */ + __asm("NOP"); /* something to use as a breakpoint stop while looping */ + } } -- cgit v1.2.3