summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/CMakeLists.txt7
-rw-r--r--app/include/FreeRTOSConfig.h197
-rw-r--r--app/include/adc_task.h20
-rw-r--r--app/include/apalis-tk1-k20-api.h123
-rw-r--r--app/include/can_task.h22
-rw-r--r--app/include/com_task.h45
-rw-r--r--app/include/gpio_ext.h22
-rw-r--r--app/src/adc_task.c365
-rw-r--r--app/src/can_task.c470
-rw-r--r--app/src/com_task.c279
-rw-r--r--app/src/gpio_ext.c132
-rw-r--r--app/src/main.c139
12 files changed, 1821 insertions, 0 deletions
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
new file mode 100644
index 0000000..2bd11c6
--- /dev/null
+++ b/app/CMakeLists.txt
@@ -0,0 +1,7 @@
+list(APPEND SOURCES
+ ${CMAKE_CURRENT_LIST_DIR}/src/adc_task.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/can_task.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/com_task.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/gpio_ext.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/main.c
+) \ No newline at end of file
diff --git a/app/include/FreeRTOSConfig.h b/app/include/FreeRTOSConfig.h
new file mode 100644
index 0000000..91e561f
--- /dev/null
+++ b/app/include/FreeRTOSConfig.h
@@ -0,0 +1,197 @@
+/*
+ FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
+ *
+ * See http://www.freertos.org/a00110.html.
+ *----------------------------------------------------------*/
+
+#define configUSE_PREEMPTION 1
+#define configUSE_TICKLESS_IDLE 0
+#define configCPU_CLOCK_HZ (SystemCoreClock)
+#define configTICK_RATE_HZ ((TickType_t)1000)
+#define configMAX_PRIORITIES 5
+#define configMINIMAL_STACK_SIZE ((unsigned short)90)
+#define configMAX_TASK_NAME_LEN 20
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_TASK_NOTIFICATIONS 1
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */
+#define configQUEUE_REGISTRY_SIZE 8
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TIME_SLICING 0
+#define configUSE_NEWLIB_REENTRANT 0
+#define configENABLE_BACKWARD_COMPATIBILITY 1
+#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
+#define configUSE_APPLICATION_TASK_TAG 0
+
+/* Memory allocation related definitions. */
+#define configSUPPORT_STATIC_ALLOCATION 0
+#define configSUPPORT_DYNAMIC_ALLOCATION 1
+#define configTOTAL_HEAP_SIZE ((size_t)(10240))
+#define configAPPLICATION_ALLOCATED_HEAP 0
+
+/* Hook function related definitions. */
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configCHECK_FOR_STACK_OVERFLOW 0
+#define configUSE_MALLOC_FAILED_HOOK 0
+#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
+
+/* Run time and task stats gathering related definitions. */
+#define configGENERATE_RUN_TIME_STATS 0
+#define configUSE_TRACE_FACILITY 1
+#define configUSE_STATS_FORMATTING_FUNCTIONS 0
+
+/* Co-routine related definitions. */
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES 2
+
+/* Software timer related definitions. */
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY 2
+#define configTIMER_QUEUE_LENGTH 10
+#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2)
+
+/* Define to trap errors during development. */
+//#define configASSERT(x) if((x) == 0) {taskDISABLE_INTERRUPTS(); for (;;);}
+
+/* Optional functions - most linkers will remove unused functions anyway. */
+#define INCLUDE_vTaskPrioritySet 1
+#define INCLUDE_uxTaskPriorityGet 1
+#define INCLUDE_vTaskDelete 1
+#define INCLUDE_vTaskSuspend 1
+#define INCLUDE_xResumeFromISR 1
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_xTaskGetSchedulerState 1
+#define INCLUDE_xTaskGetCurrentTaskHandle 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 0
+#define INCLUDE_xTaskGetIdleTaskHandle 0
+#define INCLUDE_eTaskGetState 0
+#define INCLUDE_xEventGroupSetBitFromISR 1
+#define INCLUDE_xTimerPendFunctionCall 1
+#define INCLUDE_xTaskAbortDelay 0
+#define INCLUDE_xTaskGetHandle 0
+#define INCLUDE_xTaskResumeFromISR 1
+
+#ifdef __NVIC_PRIO_BITS
+/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
+#define configPRIO_BITS __NVIC_PRIO_BITS
+#else
+#define configPRIO_BITS 4 /* 15 priority levels */
+#endif
+
+/* The lowest interrupt priority that can be used in a call to a "set priority"
+function. */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1U << (configPRIO_BITS)) - 1)
+
+/* The highest interrupt priority that can be used by any interrupt service
+routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
+INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
+PRIORITY THAN THIS! (higher priorities are lower numeric values. */
+#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
+
+/* Interrupt priorities used by the kernel port layer itself. These are generic
+to all Cortex-M ports, and do not rely on any particular library functions. */
+#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
+/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
+See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
+
+/* Normal assert() semantics without relying on the provision of an assert.h
+header file. */
+#define configASSERT(x) \
+ if ((x) == 0) \
+ { \
+ taskDISABLE_INTERRUPTS(); \
+ for (;;) \
+ ; \
+ }
+
+/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
+standard names. */
+#define vPortSVCHandler SVC_Handler
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+
+#endif /* FREERTOS_CONFIG_H */
diff --git a/app/include/adc_task.h b/app/include/adc_task.h
new file mode 100644
index 0000000..98a25aa
--- /dev/null
+++ b/app/include/adc_task.h
@@ -0,0 +1,20 @@
+/*
+ * adc_task.h
+ *
+ */
+
+#ifndef SOURCE_ADC_TASK_H_
+#define SOURCE_ADC_TASK_H_
+#include "board.h"
+#include "fsl_dspi.h"
+
+#ifdef BOARD_USES_ADC
+extern TaskHandle_t adc_task_handle;
+extern TaskHandle_t tsc_task_handle;
+void adc_task(void *pvParameters);
+void tsc_task(void *pvParameters);
+int adc_registers(dspi_transfer_t *spi_transfer);
+int tsc_registers(dspi_transfer_t *spi_transfer);
+#endif
+
+#endif /* SOURCE_ADC_TASK_H_ */
diff --git a/app/include/apalis-tk1-k20-api.h b/app/include/apalis-tk1-k20-api.h
new file mode 100644
index 0000000..112a79b
--- /dev/null
+++ b/app/include/apalis-tk1-k20-api.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2016-2017 Toradex AG
+ * Dominik Sliwa <dominik.sliwa@toradex.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef __LINUX_MFD_APALIS_TK1_K20_API_H
+#define __LINUX_MFD_APALIS_TK1_K20_API_H
+
+/* 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 250u
+#define APALIS_TK1_K20_HEADER 4u
+
+/* 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 RO(reset of read) */
+#define APALIS_TK1_K20_CTRREG 0x03 /* general control register RW */
+#define APALIS_TK1_K20_MSQREG 0x04 /* IRQ mask register RW */
+
+/* 0x05-0x0F Reserved */
+
+/* CAN Registers */
+#define APALIS_TK1_K20_CANREG 0x10 /* CAN0 control & status register RW */
+#define APALIS_TK1_K20_CANREG_CLR 0x11 /* CAN0 CANREG clear register WO */
+#define APALIS_TK1_K20_CANERR 0x12 /* CAN0 error register RW */
+#define APALIS_TK1_K20_CAN_BAUD_REG 0x13 /* CAN0 baud set register RW */
+#define APALIS_TK1_K20_CAN_BIT_1 0x14 /* CAN0 bit timing register 1 RW */
+#define APALIS_TK1_K20_CAN_BIT_2 0x15 /* CAN0 bit timing register 2 RW */
+#define APALIS_TK1_K20_CAN_IN_BUF_CNT 0x16 /* CAN0 IN received data count RO */
+#define APALIS_TK1_K20_CAN_IN_BUF 0x17 /* CAN0 IN RO */
+/* buffer size is 13 bytes */
+#define APALIS_TK1_K20_CAN_IN_BUF_END 0x23 /* CAN0 IN RO */
+#define APALIS_TK1_K20_CAN_OUT_BUF 0x24 /* CAN0 OUT WO */
+/* buffer size is 13 bytes */
+#define APALIS_TK1_K20_CAN_OUT_BUF_END (APALIS_TK1_K20_CAN_OUT_BUF + 13 - 1)/* CAN OUT BUF END */
+#define APALIS_TK1_K20_CAN_OFFSET 0x30
+#define APALIS_TK1_K20_CAN_DEV_OFFSET(x) (x ? APALIS_TK1_K20_CAN_OFFSET : 0)
+
+/* 0x30-0x3F Reserved */
+/* 0x40-0x62 CAN1 registers same layout as CAN0 */
+/* 0x63-0x6F Reserved */
+
+/* ADC Registers */
+#define APALIS_TK1_K20_ADCREG 0x70 /* ADC control & status register RW */
+#define APALIS_TK1_K20_ADC_CH0L 0x71 /* ADC Channel 0 LSB RO */
+#define APALIS_TK1_K20_ADC_CH0H 0x72 /* ADC Channel 0 MSB RO */
+#define APALIS_TK1_K20_ADC_CH1L 0x73 /* ADC Channel 1 LSB RO */
+#define APALIS_TK1_K20_ADC_CH1H 0x74 /* ADC Channel 1 MSB RO */
+#define APALIS_TK1_K20_ADC_CH2L 0x75 /* ADC Channel 2 LSB RO */
+#define APALIS_TK1_K20_ADC_CH2H 0x76 /* ADC Channel 2 MSB RO */
+#define APALIS_TK1_K20_ADC_CH3L 0x77 /* ADC Channel 3 LSB RO */
+#define APALIS_TK1_K20_ADC_CH3H 0x78 /* ADC Channel 3 MSB RO */
+/* Bulk read of LSB register can be use to read entire 16-bit in one command */
+/* Bulk read of APALIS_TK1_K20_ADC_CH0L register can be use to read all
+ * ADC channels in one command */
+
+/* 0x79-0x7F reserved */
+
+/* TSC Register */
+#define APALIS_TK1_K20_TSCREG 0x80 /* TSC control & status register RW */
+#define APALIS_TK1_K20_TSC_XML 0x81 /* TSC X- data LSB RO */
+#define APALIS_TK1_K20_TSC_XMH 0x82 /* TSC X- data MSB RO */
+#define APALIS_TK1_K20_TSC_XPL 0x83 /* TSC X+ data LSB RO */
+#define APALIS_TK1_K20_TSC_XPH 0x84 /* TSC X+ data MSB RO */
+#define APALIS_TK1_K20_TSC_YML 0x85 /* TSC Y- data LSB RO */
+#define APALIS_TK1_K20_TSC_YMH 0x86 /* TSC Y- data MSB RO */
+#define APALIS_TK1_K20_TSC_YPL 0x87 /* TSC Y+ data LSB RO */
+#define APALIS_TK1_K20_TSC_YPH 0x88 /* 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 BIT(0)
+
+/* 0x89-0x8F Reserved */
+
+/* GPIO Registers */
+#define APALIS_TK1_K20_GPIOREG 0x90 /* GPIO control & status register RW */
+#define APALIS_TK1_K20_GPIO_NO 0x91 /* currently configured GPIO RW */
+#define APALIS_TK1_K20_GPIO_STA 0x92 /* 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)
+
+/* 0x93-0xFC Reserved */
+#define APALIS_TK1_K20_LAST_REG 0xFD
+#define APALIS_TK1_K20_RET_REQ 0xFE
+/* 0xFF Reserved */
+
+/* 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 0x12
+#define APALIS_TK1_K20_TESTER_FW_VER 0xFE
+
+#define FW_MINOR (APALIS_TK1_K20_FW_VER & 0x0F)
+#define FW_MAJOR ((APALIS_TK1_K20_FW_VER & 0xF0) >> 4)
+
+#define TK1_K20_SENTINEL 0x55
+#define TK1_K20_INVAL 0xAA
+
+#define APALIS_TK1_K20_IRQ_REG_CNT 1
+#define APALIS_TK1_K20_IRQ_PER_REG 8
+
+#define APALIS_TK1_CAN_CLK_UNIT 6250
+
+#define APALIS_TK1_MAX_CAN_DMA_XREF 19u
+
+#endif /* ifndef __LINUX_MFD_APALIS_TK1_K20_API_H */
diff --git a/app/include/can_task.h b/app/include/can_task.h
new file mode 100644
index 0000000..8934c0a
--- /dev/null
+++ b/app/include/can_task.h
@@ -0,0 +1,22 @@
+/*
+ * can_task.h
+ */
+
+#ifndef SOURCE_CAN_TASK_H_
+#define SOURCE_CAN_TASK_H_
+
+/* FreeRTOS kernel includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "fsl_dspi.h"
+
+extern TaskHandle_t can0_task_handle;
+extern TaskHandle_t can1_task_handle;
+extern TaskHandle_t can_tx_notify_task_handle;
+void can0_task(void *pvParameters);
+void can1_task(void *pvParameters);
+void can_tx_notify_task(void *pvParameters);
+int canx_registers(dspi_transfer_t *spi_transfer, int id);
+void can_spi_read_complete(uint8_t id);
+
+#endif /* SOURCE_CAN_TASK_H_ */
diff --git a/app/include/com_task.h b/app/include/com_task.h
new file mode 100644
index 0000000..a541f88
--- /dev/null
+++ b/app/include/com_task.h
@@ -0,0 +1,45 @@
+/*
+ * 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"
+#include "fsl_edma.h"
+#include "fsl_dspi_edma.h"
+#include "fsl_dmamux.h"
+#include "apalis-tk1-k20-api.h"
+
+/* FreeRTOS kernel includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "timers.h"
+#include "semphr.h"
+#include "errno.h"
+
+#define SPI_DMA
+
+typedef struct _callback_message_t
+{
+ status_t async_status;
+ SemaphoreHandle_t sem;
+} callback_message_t;
+
+extern 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))
+#define ADC0_CHANNEL_CNT 4
+#define TSC0_CHANNEL_CNT 4
+#define CAN_RX_BUF_SIZE 256
+
+extern volatile uint8_t registers[APALIS_TK1_K20_LAST_REG];
+
+#endif /* COM_TASK_H_ */
diff --git a/app/include/gpio_ext.h b/app/include/gpio_ext.h
new file mode 100644
index 0000000..7fe800d
--- /dev/null
+++ b/app/include/gpio_ext.h
@@ -0,0 +1,22 @@
+/*
+ * gpio_ext.h
+ *
+ */
+
+#ifndef SOURCE_GPIO_EXT_H_
+#define SOURCE_GPIO_EXT_H_
+
+#include "board.h"
+#include "fsl_device_registers.h"
+#include "fsl_debug_console.h"
+#include "fsl_dspi.h"
+
+struct gpio_id{
+ PORT_Type *port;
+ GPIO_Type *gpio;
+ uint32_t pin;
+};
+
+int gpio_registers(dspi_transfer_t *spi_transfer);
+
+#endif /* SOURCE_GPIO_EXT_H_ */
diff --git a/app/src/adc_task.c b/app/src/adc_task.c
new file mode 100644
index 0000000..daf4716
--- /dev/null
+++ b/app/src/adc_task.c
@@ -0,0 +1,365 @@
+/*
+ * 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"
+
+struct adc_data {
+ uint16_t adc[ADC0_CHANNEL_CNT];
+ uint16_t tsc_xm;
+ uint16_t tsc_xp;
+ uint16_t tsc_ym;
+ uint16_t tsc_yp;
+} adc_data;
+
+/*
+ * 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);
+ PRINTF("ADC init done \r\n");
+ 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_LongSampleCycle10;
+ adc_config.clockDivider = kADC16_ClockDivider8;
+ ADC16_Init(ADC1, &adc_config);
+ ADC16_SetChannelMuxMode(ADC1, kADC16_ChannelMuxB);
+ ADC16_SetHardwareAverage(ADC1, kADC16_HardwareAverageCount32);
+ PRINTF("TSC init done \r\n");
+ 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];
+ adc_data.adc[i] = do_adc_conversion(ADC0, &channel);
+ registers[APALIS_TK1_K20_ADC_CH0L + 2 * i] = adc_data.adc[i] & 0xFF;
+ registers[APALIS_TK1_K20_ADC_CH0L + 2 * i + 1] = (adc_data.adc[i] >> 8) & 0xFF;
+ }
+ vTaskDelay(5);
+ }
+
+}
+
+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, press;
+ uint16_t tsc_xm;
+ uint16_t tsc_xp;
+ uint16_t tsc_ym;
+ uint16_t tsc_yp;
+
+ if (tsc_task_init() < 0)
+ return;
+
+ pin_config_pd.mux = kPORT_MuxAsGpio;
+ pin_config_pd.openDrainEnable = kPORT_OpenDrainDisable;
+ pin_config_pd.pullSelect = kPORT_PullUp;
+ 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 pullup on xp and read xp GPIO
+ ts_force_drive(0, 0, 1, 0);
+ PORT_SetPinConfig(PORTB, 6u, &pin_config_pd);
+ vTaskDelay(5);
+ old_status = status;
+ status = GPIO_ReadPinInput(GPIOB, 6u) ? PEN_UP:PEN_DOWN;
+ 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);
+ channel.channelNumber = tsc_channels[0];
+ tsc_ym = do_adc_conversion(ADC1, &channel);
+
+ //probe yp with power across Y plane
+ channel.channelNumber = tsc_channels[1];
+ tsc_yp = do_adc_conversion(ADC1, &channel);
+
+ //probe xm with power across X plane
+ ts_force_drive(1, 1, 0, 0);
+ channel.channelNumber = tsc_channels[2];
+ tsc_xm = do_adc_conversion(ADC1, &channel);
+
+ //probe xp with power across X plane
+ channel.channelNumber = tsc_channels[3];
+ tsc_xp = do_adc_conversion(ADC1, &channel);
+
+#ifdef TOUCH_STRONG_FILTERING
+ /* additional filtering */
+ //probe ym with power across Y plane
+ ts_force_drive(0, 0, 1, 1);
+ channel.channelNumber = tsc_channels[0];
+ tsc_ym += do_adc_conversion(ADC1, &channel);
+ tsc_ym >>= 1;
+
+ //probe yp with power across Y plane
+ channel.channelNumber = tsc_channels[1];
+ tsc_yp += do_adc_conversion(ADC1, &channel);
+ tsc_yp >>= 1;
+
+ //probe xm with power across X plane
+ ts_force_drive(1, 1, 0, 0);
+ channel.channelNumber = tsc_channels[2];
+ tsc_xm += do_adc_conversion(ADC1, &channel);
+ tsc_xm >>= 1;
+
+ //probe xp with power across X plane
+ channel.channelNumber = tsc_channels[3];
+ tsc_xp += do_adc_conversion(ADC1, &channel);
+ tsc_xp >>= 1;
+#endif
+
+ /* make sure that pen is making good contact */
+ press = (abs(tsc_yp - tsc_ym)
+ + abs(tsc_xp - tsc_xm)) / 2;
+#ifdef TOUCH_STRONG_FILTERING
+ if (press > 9) {
+#else
+ if (press > 15) {
+#endif
+ continue;
+ } else {
+ adc_data.tsc_xm = tsc_xm;
+ adc_data.tsc_xp = tsc_xp;
+ adc_data.tsc_ym = tsc_ym;
+ adc_data.tsc_yp = tsc_yp;
+ }
+
+ } else {
+ adc_data.tsc_xm = 0;
+ adc_data.tsc_xp = 0;
+ adc_data.tsc_ym = 0;
+ adc_data.tsc_yp = 0;
+ vTaskDelay(10);
+ }
+
+ if (irq_stat == 0) {
+ generate_irq(APALIS_TK1_K20_TSC_IRQ);
+ irq_stat = 1;
+ }
+
+ vTaskDelay(5);
+ }
+
+}
+
+int tsc_registers(dspi_transfer_t *spi_transfer)
+{
+ uint8_t *rx_buf = spi_transfer->rxData;
+ uint8_t *tx_buf = &spi_transfer->txData[0];
+
+ if (rx_buf[0] == APALIS_TK1_K20_WRITE_INST) {
+ switch (rx_buf[1]) {
+ case APALIS_TK1_K20_TSCREG:
+ return 0;
+ default:
+ return -ENOENT;
+ }
+ } else if (rx_buf[0] == APALIS_TK1_K20_BULK_READ_INST) {
+ if (rx_buf[1] == APALIS_TK1_K20_TSC_XML) {
+ if (rx_buf[2] == 2) {
+ tx_buf[0] = adc_data.tsc_xm & 0xFF;
+ tx_buf[1] = (adc_data.tsc_xm >> 8) & 0xFF;
+ return 2;
+ } else if (rx_buf[2] == 8) {
+ tx_buf[0] = adc_data.tsc_xm & 0xFF;
+ tx_buf[1] = (adc_data.tsc_xm >> 8) & 0xFF;
+ tx_buf[2] = adc_data.tsc_xp & 0xFF;
+ tx_buf[3] = (adc_data.tsc_xp >> 8) & 0xFF;
+ tx_buf[4] = adc_data.tsc_ym & 0xFF;
+ tx_buf[5] = (adc_data.tsc_ym >> 8) & 0xFF;
+ tx_buf[6] = adc_data.tsc_yp & 0xFF;
+ tx_buf[7] = (adc_data.tsc_yp >> 8) & 0xFF;
+ return 8;
+ }
+ }
+ switch (rx_buf[1]) {
+ case APALIS_TK1_K20_TSC_XPL:
+ tx_buf[0] = adc_data.tsc_xp & 0xFF;
+ tx_buf[1] = (adc_data.tsc_xp >> 8) & 0xFF;
+ return 2;
+ case APALIS_TK1_K20_TSC_YML:
+ tx_buf[0] = adc_data.tsc_ym & 0xFF;
+ tx_buf[1] = (adc_data.tsc_ym >> 8) & 0xFF;
+ return 2;
+ case APALIS_TK1_K20_TSC_YPL:
+ tx_buf[0] = adc_data.tsc_yp & 0xFF;
+ tx_buf[1] = (adc_data.tsc_yp >> 8) & 0xFF;
+ return 2;
+ default:
+ return -ENOENT;
+ }
+ }
+ return -ENOENT;
+}
+
+int adc_registers(dspi_transfer_t *spi_transfer)
+{
+ uint8_t *rx_buf = spi_transfer->rxData;
+ uint8_t *tx_buf = &spi_transfer->txData[0];
+
+ if (rx_buf[0] == APALIS_TK1_K20_WRITE_INST) {
+ switch (rx_buf[1]) {
+ case APALIS_TK1_K20_ADCREG:
+ return 0;
+ default:
+ return -ENOENT;
+ }
+ } else if (rx_buf[0] == APALIS_TK1_K20_BULK_READ_INST) {
+ if (rx_buf[1] == APALIS_TK1_K20_ADC_CH0L) {
+ if (rx_buf[2] == 2) {
+ tx_buf[0] = adc_data.adc[0] & 0xFF;
+ tx_buf[1] = (adc_data.adc[0] >> 8) & 0xFF;
+ return 2;
+ } else if (rx_buf[2] == 8) {
+ tx_buf[0] = adc_data.adc[0] & 0xFF;
+ tx_buf[1] = (adc_data.adc[0] >> 8) & 0xFF;
+ tx_buf[2] = adc_data.adc[1] & 0xFF;
+ tx_buf[3] = (adc_data.adc[1] >> 8) & 0xFF;
+ tx_buf[4] = adc_data.adc[2] & 0xFF;
+ tx_buf[5] = (adc_data.adc[2] >> 8) & 0xFF;
+ tx_buf[6] = adc_data.adc[3] & 0xFF;
+ tx_buf[7] = (adc_data.adc[3] >> 8) & 0xFF;
+ return 8;
+ }
+ }
+ switch (rx_buf[1]){
+ case APALIS_TK1_K20_ADC_CH1L:
+ tx_buf[0] = adc_data.adc[1] & 0xFF;
+ tx_buf[1] = (adc_data.adc[1] >> 8) & 0xFF;
+ return 2;
+ case APALIS_TK1_K20_ADC_CH2L:
+ tx_buf[0] = adc_data.adc[2] & 0xFF;
+ tx_buf[1] = (adc_data.adc[2] >> 8) & 0xFF;
+ return 2;
+ case APALIS_TK1_K20_ADC_CH3L:
+ tx_buf[0] = adc_data.adc[3] & 0xFF;
+ tx_buf[1] = (adc_data.adc[3] >> 8) & 0xFF;
+ return 2;
+
+ default:
+ return -ENOENT;
+ }
+ }
+ return -ENOENT;
+}
+#endif
diff --git a/app/src/can_task.c b/app/src/can_task.c
new file mode 100644
index 0000000..e34d35d
--- /dev/null
+++ b/app/src/can_task.c
@@ -0,0 +1,470 @@
+
+#include "can_task.h"
+#include "com_task.h"
+#include "fsl_flexcan.h"
+
+/* special address description flags for the CAN_ID */
+#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
+#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
+#define CAN_ERR_FLAG 0x20000000U /* error message frame */
+
+#define TX_MESSAGE_BUFFER_NUM0 (9)
+
+#define CAN_FRAME_MAX_LEN 8
+#define CAN_HEADER_MAX_LEN 5
+#define CAN_TRANSFER_BUF_LEN (CAN_HEADER_MAX_LEN + CAN_FRAME_MAX_LEN)
+
+#define CANCTRL_MODMASK (BIT(1) | BIT(0))
+#define CANCTRL_INTEN BIT(2)
+#define CANINTF_RX BIT(3)
+#define CANINTF_TX BIT(4)
+#define CANINTF_ERR BIT(5)
+#define CANCTRL_ENABLE BIT(6)
+#define CANCTRL_INTMASK (CANINTF_RX | CANINTF_TX | CANINTF_ERR)
+
+#define EFLG_EWARN 0x01
+#define EFLG_RXWAR 0x02
+#define EFLG_TXWAR 0x04
+#define EFLG_RXEP 0x08
+#define EFLG_TXEP 0x10
+#define EFLG_TXBO 0x20
+#define EFLG_RXOVR 0x40
+
+struct can_registers {
+ CAN_Type *base;
+ flexcan_handle_t handle;
+ uint8_t can_enable;
+ uint8_t can_err_reg;
+ uint8_t can_mode;
+ uint8_t frames_in_buf;
+ uint8_t rx_buf_top;
+ uint8_t rx_buf_bottom;
+ uint8_t tx_counter;
+};
+
+static uint8_t data_buffer[2][CAN_RX_BUF_SIZE][CAN_TRANSFER_BUF_LEN];
+
+static struct can_registers can_regs[2];
+
+static inline void generate_can_irq(uint8_t id)
+{
+ if (id == 0) {
+ GPIO_TogglePinsOutput(GPIOB, 1u << 8u);
+ } else {
+ GPIO_TogglePinsOutput(GPIOE, 1u << 26u);
+ }
+}
+
+void can_tx_notify_task(void *pvParameters)
+{
+ uint32_t ulInterruptStatus;
+
+ while(1){
+ xTaskNotifyWait( 0x00, 0xFFFFFFFF, &ulInterruptStatus, portMAX_DELAY);
+ if (ulInterruptStatus & 0x01) {
+ registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(0)] &= ~CANINTF_TX;
+ generate_can_irq(0);
+ }
+ if (ulInterruptStatus & 0x02) {
+ registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(1)] &= ~CANINTF_TX;
+ generate_can_irq(1);
+ }
+ if (ulInterruptStatus & 0x04) {
+ registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(0)] |= CANINTF_ERR;
+ generate_can_irq(0);
+ }
+ if (ulInterruptStatus & 0x08) {
+ registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(1)] |= CANINTF_ERR;
+ generate_can_irq(1);
+ }
+ }
+}
+
+static BaseType_t flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData)
+{
+ callback_message_t * cb = (callback_message_t*) userData;
+ BaseType_t reschedule = pdFALSE;
+
+ switch (status)
+ {
+ case kStatus_FLEXCAN_RxFifoIdle:
+ cb->async_status = pdTRUE;
+ xSemaphoreGiveFromISR(cb->sem, &reschedule);
+ break;
+
+ case kStatus_FLEXCAN_TxIdle:
+ if (TX_MESSAGE_BUFFER_NUM0 == result)
+ {
+ switch ((int)base)
+ {
+ case (int)CAN0:
+
+ xTaskNotifyFromISR(can_tx_notify_task_handle, 0x01, eSetBits, &reschedule);
+ break;
+ case (int)CAN1:
+ xTaskNotifyFromISR(can_tx_notify_task_handle, 0x02, eSetBits, &reschedule);
+ break;
+ }
+
+ }
+ break;
+
+ case kStatus_FLEXCAN_ErrorStatus:
+ if ((result & (kFLEXCAN_TxWarningIntFlag)) != 0) {
+ switch ((int)base)
+ {
+ case (int)CAN0:
+ registers[APALIS_TK1_K20_CANERR + APALIS_TK1_K20_CAN_DEV_OFFSET(0)] |= EFLG_TXWAR;
+ xTaskNotifyFromISR(can_tx_notify_task_handle, 0x04, eSetBits, &reschedule);
+ break;
+ case (int)CAN1:
+ registers[APALIS_TK1_K20_CANERR + APALIS_TK1_K20_CAN_DEV_OFFSET(1)] |= EFLG_TXWAR;
+ xTaskNotifyFromISR(can_tx_notify_task_handle, 0x08, eSetBits, &reschedule);
+ break;
+ }
+ }
+
+ if ((result & (kFLEXCAN_BusOffIntFlag)) != 0) {
+ switch ((int)base)
+ {
+ case (int)CAN0:
+ registers[APALIS_TK1_K20_CANERR + APALIS_TK1_K20_CAN_DEV_OFFSET(0)] |= EFLG_TXBO;
+ xTaskNotifyFromISR(can_tx_notify_task_handle, 0x04, eSetBits, &reschedule);
+ break;
+ case (int)CAN1:
+ registers[APALIS_TK1_K20_CANERR + APALIS_TK1_K20_CAN_DEV_OFFSET(1)] |= EFLG_TXBO;
+ xTaskNotifyFromISR(can_tx_notify_task_handle, 0x08, eSetBits, &reschedule);
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return reschedule;
+}
+
+static void CAN_Init(uint8_t id)
+{
+ flexcan_config_t flexcanConfig;
+ flexcan_rx_fifo_config_t fifoConfig;
+ uint32_t fifoFilter = 0xFFFFFFFF;
+
+ FLEXCAN_GetDefaultConfig(&flexcanConfig);
+
+ flexcanConfig.baudRate = 1000000U; /* set default to 1Mbit/s*/
+
+ /* Init FlexCAN module. */
+ flexcanConfig.clkSrc = kFLEXCAN_ClkSrcPeri;
+ FLEXCAN_Init(can_regs[id].base, &flexcanConfig, CLOCK_GetFreq(kCLOCK_BusClk));
+
+ /* Create FlexCAN handle structure and set call back function. */
+ FLEXCAN_TransferCreateHandle(can_regs[id].base, &can_regs[id].handle, flexcan_callback,
+ can_regs[id].handle.userData);
+
+ /* Set Rx Mask to don't care on all bits. */
+ FLEXCAN_SetRxMbGlobalMask(can_regs[id].base, FLEXCAN_RX_MB_EXT_MASK(0x00, 0, 0));
+ FLEXCAN_SetRxFifoGlobalMask(can_regs[id].base, FLEXCAN_RX_MB_EXT_MASK(0x00, 0, 0));
+
+ fifoConfig.idFilterNum = 0;
+ fifoConfig.idFilterTable = &fifoFilter;
+ fifoConfig.idFilterType = kFLEXCAN_RxFifoFilterTypeC;
+ fifoConfig.priority = kFLEXCAN_RxFifoPrioHigh;
+ FLEXCAN_SetRxFifoConfig(can_regs[id].base, &fifoConfig, true);
+
+ /* errata #5641 */
+ can_regs[id].base->MB[TX_MESSAGE_BUFFER_NUM0 - 1].ID = 0x0;
+ can_regs[id].base->MB[TX_MESSAGE_BUFFER_NUM0 - 1].WORD0 = 0x0;
+ can_regs[id].base->MB[TX_MESSAGE_BUFFER_NUM0 - 1].WORD1 = 0x0;
+ can_regs[id].base->MB[TX_MESSAGE_BUFFER_NUM0 - 1].CS = CAN_CS_CODE(0x8);
+ can_regs[id].base->MB[TX_MESSAGE_BUFFER_NUM0 - 1].CS = CAN_CS_CODE(0x8);
+
+ /* Setup Tx Message Buffer. */
+ FLEXCAN_SetTxMbConfig(can_regs[id].base, TX_MESSAGE_BUFFER_NUM0, true);
+}
+
+uint8_t available_data[2];
+
+static void can_calculate_available_data(uint8_t id) {
+ taskENTER_CRITICAL();
+ if ( can_regs[id].rx_buf_bottom <= can_regs[id].rx_buf_top)
+ available_data[id] = can_regs[id].rx_buf_top - can_regs[id].rx_buf_bottom;
+ else
+ available_data[id] = CAN_RX_BUF_SIZE - can_regs[id].rx_buf_bottom;
+
+ available_data[id] = (available_data[id] > APALIS_TK1_MAX_CAN_DMA_XREF) ? APALIS_TK1_MAX_CAN_DMA_XREF:available_data[id];
+ registers[APALIS_TK1_K20_CAN_IN_BUF_CNT + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] = available_data[id];
+
+ if (can_regs[id].rx_buf_bottom == can_regs[id].rx_buf_top)
+ registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] &= ~CANINTF_RX;
+ else
+ registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] |= CANINTF_RX;
+ taskEXIT_CRITICAL();
+}
+
+void can_spi_read_complete(uint8_t id)
+{
+ can_calculate_available_data(id);
+}
+
+static void frame_to_buffer(flexcan_frame_t *frame, uint8_t id) {
+ uint8_t top_frame = can_regs[id].rx_buf_top;
+ switch (frame->format){
+ case kFLEXCAN_FrameFormatExtend:
+ data_buffer[id][top_frame][0] = frame->id & 0xFF;
+ data_buffer[id][top_frame][1] = (frame->id >> 8 ) & 0xFF;
+ data_buffer[id][top_frame][2] = (frame->id >> 16 ) & 0xFF;
+ data_buffer[id][top_frame][3] = (frame->id >> 24 ) & 0x1F;
+ data_buffer[id][top_frame][3] |= CAN_EFF_FLAG >> 24;
+ break;
+ case kFLEXCAN_FrameFormatStandard:
+ data_buffer[id][top_frame][0] = (frame->id >> 18) & 0xFF;
+ data_buffer[id][top_frame][1] = ((frame->id >> 18) >> 8 ) & 0x7F;
+ data_buffer[id][top_frame][2] = 0x00;
+ data_buffer[id][top_frame][3] = 0x00;
+ break;
+ }
+
+ data_buffer[id][top_frame][3] |= frame->type ? (CAN_RTR_FLAG >> 24):0x00;
+ data_buffer[id][top_frame][4] = frame->length;
+
+ switch (frame->length) {
+ case 8:data_buffer[id][top_frame][5 + 7] = frame->dataByte7;
+ case 7:data_buffer[id][top_frame][5 + 6] = frame->dataByte6;
+ case 6:data_buffer[id][top_frame][5 + 5] = frame->dataByte5;
+ case 5:data_buffer[id][top_frame][5 + 4] = frame->dataByte4;
+ case 4:data_buffer[id][top_frame][5 + 3] = frame->dataByte3;
+ case 3:data_buffer[id][top_frame][5 + 2] = frame->dataByte2;
+ case 2:data_buffer[id][top_frame][5 + 1] = frame->dataByte1;
+ case 1:data_buffer[id][top_frame][5] = frame->dataByte0;
+ }
+
+ can_regs[id].rx_buf_top++;
+ can_regs[id].rx_buf_top %= CAN_RX_BUF_SIZE;
+
+ can_calculate_available_data(id);
+}
+
+static inline void can_fifo_rx(uint8_t id, flexcan_fifo_transfer_t * rxXfer)
+{
+ callback_message_t *can_msg = (callback_message_t *) can_regs[id].handle.userData;
+
+ FLEXCAN_TransferReceiveFifoNonBlocking(can_regs[id].base, &can_regs[id].handle, rxXfer);
+ xSemaphoreTake(can_msg->sem, portMAX_DELAY);
+ if (can_msg->async_status == pdTRUE) {
+ frame_to_buffer(rxXfer->frame, id);
+ can_regs[id].frames_in_buf++;
+ generate_can_irq(id);
+ if (can_regs[id].frames_in_buf >= CAN_RX_BUF_SIZE)
+ vTaskSuspend(NULL);
+ }
+}
+
+void can0_task(void *pvParameters) {
+ flexcan_frame_t rxFrame;
+ flexcan_fifo_transfer_t rxXfer;
+ callback_message_t can_msg;
+
+ can_msg.sem = xSemaphoreCreateBinary();
+ can_msg.async_status = pdFALSE;
+ memset(&can_regs[0], 0x00u, sizeof(struct can_registers));
+ can_regs[0].handle.userData = (void *) &can_msg;
+ can_regs[0].base = CAN0;
+
+ CAN_Init(0);
+ PRINTF("CAN0 init done \r\n");
+
+ rxXfer.frame = &rxFrame;
+
+ while(1)
+ {
+ can_fifo_rx(0, &rxXfer);
+ }
+ vSemaphoreDelete(can_msg.sem);
+}
+
+void can1_task(void *pvParameters) {
+ flexcan_frame_t rxFrame;
+ flexcan_fifo_transfer_t rxXfer;
+ callback_message_t can_msg;
+
+ can_msg.sem = xSemaphoreCreateBinary();
+ can_msg.async_status = pdFALSE;
+ memset(&can_regs[1], 0x00u, sizeof(struct can_registers));
+ can_regs[1].handle.userData = (void *) &can_msg;
+ can_regs[1].base = CAN1;
+
+ CAN_Init(1);
+ PRINTF("CAN1 init done \r\n");
+ rxXfer.frame = &rxFrame;
+
+ while(1)
+ {
+ can_fifo_rx(1, &rxXfer);
+ }
+ vSemaphoreDelete(can_msg.sem);
+
+}
+
+static void can_change_mode(int id, uint8_t new_mode)
+{
+ can_regs[id].can_mode = new_mode;
+
+ FLEXCAN_SetMode(can_regs[id].base, new_mode);
+
+}
+
+static void can_enable(int id, uint8_t enable)
+{
+ can_regs[id].can_mode = enable;
+
+ if (enable) {
+ callback_message_t *can_msg = (callback_message_t *) can_regs[id].handle.userData;
+ FLEXCAN_ExitFreezeMode(can_regs[id].base);
+ can_msg->async_status = pdFALSE;
+ xSemaphoreGive(can_msg->sem);
+ generate_can_irq(id);
+ } else {
+ FLEXCAN_TransferAbortReceiveFifo(can_regs[id].base, &can_regs[id].handle);
+ FLEXCAN_EnterFreezeMode(can_regs[id].base);
+ }
+
+}
+
+static uint8_t set_canreg (int id, uint8_t value)
+{
+ registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] = value;
+ if ( can_regs[id].can_mode != (value & CANCTRL_MODMASK) )
+ can_change_mode(id, (value & CANCTRL_MODMASK));
+ if (can_regs[id].can_enable != (value & CANCTRL_ENABLE))
+ can_enable(id, (value & CANCTRL_ENABLE));
+ return 0;
+}
+
+static uint8_t clr_canreg (int id, uint8_t mask)
+{
+ mask &= (CANINTF_RX | CANINTF_TX | CANINTF_ERR);
+ registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] &= ~mask;
+ return 0;
+}
+
+static uint8_t set_canerr (int id, uint8_t value)
+{
+ registers[APALIS_TK1_K20_CANERR + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] = value;
+ return 0;
+}
+
+static uint8_t set_canbadreg (int id, uint8_t value)
+{
+
+ FLEXCAN_SetBitRate(can_regs[id].base, CLOCK_GetFreq(kCLOCK_BusClk), value * APALIS_TK1_CAN_CLK_UNIT);
+ return 0;
+}
+
+static uint8_t set_canbittiming (int id, uint16_t value, int16_t mask)
+{
+ /* According to NXP we should use default settings */
+ return 0;
+}
+
+uint8_t can_sendframe(uint8_t id, uint8_t *data, uint8_t len)
+{
+ flexcan_mb_transfer_t txXfer;
+ flexcan_frame_t tx_frame;
+
+ tx_frame.length = data[4];
+ tx_frame.id = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
+
+ tx_frame.format = (data[3] << 24 & CAN_EFF_FLAG) ?
+ kFLEXCAN_FrameFormatExtend:kFLEXCAN_FrameFormatStandard;
+ tx_frame.type = (data[3] << 24 & CAN_RTR_FLAG) ?
+ kFLEXCAN_FrameTypeRemote:kFLEXCAN_FrameTypeData;
+
+ if (tx_frame.format == kFLEXCAN_FrameFormatExtend)
+ tx_frame.id = FLEXCAN_ID_EXT(tx_frame.id);
+ else
+ tx_frame.id = FLEXCAN_ID_STD(tx_frame.id);
+
+ tx_frame.dataByte0 = data[5];
+ tx_frame.dataByte1 = data[5 + 1];
+ tx_frame.dataByte2 = data[5 + 2];
+ tx_frame.dataByte3 = data[5 + 3];
+ tx_frame.dataByte4 = data[5 + 4];
+ tx_frame.dataByte5 = data[5 + 5];
+ tx_frame.dataByte6 = data[5 + 6];
+ tx_frame.dataByte7 = data[5 + 7];
+
+ txXfer.frame = &tx_frame;
+ txXfer.mbIdx = TX_MESSAGE_BUFFER_NUM0;
+ if( tx_frame.length <= 8 ) {
+ FLEXCAN_TransferSendNonBlocking(can_regs[id].base , &can_regs[id].handle, &txXfer);
+ registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] |= CANINTF_TX;
+ return 0;
+ }
+ else {
+ registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] &= ~CANINTF_TX;
+ generate_can_irq(id);
+ return -EIO;
+ }
+}
+
+uint16_t can_readframe(uint8_t id, dspi_transfer_t *spi_transfer)
+{
+ uint8_t rx_size;
+ spi_transfer->txData = data_buffer[id][can_regs[id].rx_buf_bottom];
+ rx_size = spi_transfer->rxData[2] / CAN_TRANSFER_BUF_LEN; /* size in frames, not bytes */
+ if (rx_size > available_data[id])
+ rx_size = available_data[id];
+
+ can_regs[id].rx_buf_bottom = can_regs[id].rx_buf_bottom + rx_size;
+ can_regs[id].rx_buf_bottom %= CAN_RX_BUF_SIZE;
+
+ can_regs[id].frames_in_buf -= rx_size;
+
+ return rx_size * CAN_TRANSFER_BUF_LEN;
+}
+
+int canx_registers(dspi_transfer_t *spi_transfer, int id)
+{
+ uint8_t *rx_buf = spi_transfer->rxData;
+ if (rx_buf[0] == APALIS_TK1_K20_WRITE_INST) {
+ rx_buf[1] -= APALIS_TK1_K20_CAN_DEV_OFFSET(id);
+ switch (rx_buf[1]) {
+ case APALIS_TK1_K20_CANREG:
+ return set_canreg(id, rx_buf[2]);
+ case APALIS_TK1_K20_CANREG_CLR:
+ return clr_canreg(id, rx_buf[2]);
+ case APALIS_TK1_K20_CANERR:
+ return set_canerr(id, rx_buf[2]);
+ case APALIS_TK1_K20_CAN_BAUD_REG:
+ return set_canbadreg(id, rx_buf[2]);
+ case APALIS_TK1_K20_CAN_BIT_1:
+ return set_canbittiming(id, rx_buf[2], 0x00FF);
+ case APALIS_TK1_K20_CAN_BIT_2:
+ return set_canbittiming(id, (rx_buf[2] << 8), 0xFF00);
+ default:
+ return -EIO;
+ }
+
+ } else if (rx_buf[0] == APALIS_TK1_K20_BULK_READ_INST) {
+ rx_buf[1] -= APALIS_TK1_K20_CAN_DEV_OFFSET(id);
+ switch (rx_buf[1]) {
+ case APALIS_TK1_K20_CAN_IN_BUF:
+ return can_readframe(id, spi_transfer);
+ default:
+ return -EIO;
+ }
+ } else if (rx_buf[0] == APALIS_TK1_K20_BULK_WRITE_INST) {
+ rx_buf[1] -= APALIS_TK1_K20_CAN_DEV_OFFSET(id);
+ switch (rx_buf[1]) {
+ case APALIS_TK1_K20_CAN_OUT_BUF:
+ can_sendframe(id, &rx_buf[3], rx_buf[2]);
+ return 0;
+ default:
+ return -EIO;
+ }
+ }
+ return -EIO;
+}
+
diff --git a/app/src/com_task.c b/app/src/com_task.c
new file mode 100644
index 0000000..d6bc97d
--- /dev/null
+++ b/app/src/com_task.c
@@ -0,0 +1,279 @@
+
+#include "com_task.h"
+#include "can_task.h"
+#include "gpio_ext.h"
+#include "adc_task.h"
+
+volatile uint8_t registers[APALIS_TK1_K20_LAST_REG];
+volatile uint8_t regRxHandled;
+
+/* Put FW version at known address in a binary. Make it 32-bit to have room for the future */
+#ifndef TESTER_BUILD
+const uint32_t __attribute__((section(".FwVersion"), used)) fw_version = APALIS_TK1_K20_FW_VER;
+#else
+const uint32_t __attribute__((section(".FwVersion"), used)) fw_version = APALIS_TK1_K20_TESTER_FW_VER;
+#endif
+
+static dspi_slave_handle_t spi_handle;
+static uint8_t slaveRxData[APALIS_TK1_K20_MAX_BULK + APALIS_TK1_K20_HEADER];
+static uint8_t slaveTxData[APALIS_TK1_K20_MAX_BULK + APALIS_TK1_K20_HEADER];
+
+#ifdef SPI_DMA
+dspi_slave_edma_handle_t g_dspi_edma_s_handle;
+edma_handle_t dspiEdmaSlaveRxHandle;
+edma_handle_t dspiEdmaSlaveTxHandle;
+#endif
+
+void generate_irq(uint8_t irq) {
+ if (!(registers[APALIS_TK1_K20_MSQREG] & BIT(irq))) {
+ taskENTER_CRITICAL();
+ registers[APALIS_TK1_K20_IRQREG] |= BIT(irq);
+ /* Toggle INT1 pin */
+ GPIO_TogglePinsOutput(GPIOA, 1u << 16u);
+ taskEXIT_CRITICAL();
+ }
+}
+
+void clear_irq_flag(uint8_t irq) {
+ registers[APALIS_TK1_K20_IRQREG] &= ~irq;
+}
+
+uint8_t get_control_reg()
+{
+ return registers[APALIS_TK1_K20_CTRREG];
+
+}
+
+void set_control_reg(uint8_t value)
+{
+ registers[APALIS_TK1_K20_CTRREG] = value;
+}
+
+uint8_t get_status_reg()
+{
+ return registers[APALIS_TK1_K20_STAREG];
+
+}
+
+void set_status_reg(uint8_t value)
+{
+ registers[APALIS_TK1_K20_STAREG] = value;
+}
+
+uint8_t get_mask_reg()
+{
+ return registers[APALIS_TK1_K20_MSQREG];
+
+}
+
+void set_mask_reg(uint8_t value)
+{
+ registers[APALIS_TK1_K20_MSQREG] = value;
+}
+
+uint8_t get_irq_reg()
+{
+ return registers[APALIS_TK1_K20_IRQREG];
+
+}
+
+void set_irq_reg(uint8_t value)
+{
+ /* Clear IRQ flag on 1 */
+ clear_irq_flag(value);
+
+}
+
+inline int general_registers(dspi_transfer_t * spi_transfer)
+{
+ uint8_t *rx_buf = spi_transfer->rxData;
+
+ 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 1;
+ case APALIS_TK1_K20_REVREG:
+ return -ENOENT;
+ case APALIS_TK1_K20_IRQREG:
+ set_irq_reg(rx_buf[2]);
+ return 1;
+ case APALIS_TK1_K20_CTRREG:
+ set_control_reg(rx_buf[2]);
+ return 1;
+ case APALIS_TK1_K20_MSQREG:
+ set_mask_reg(rx_buf[2]);
+ return 1;
+ default:
+ return -ESRCH;
+ }
+ }
+
+
+ return -ENXIO;
+}
+
+
+inline void SPI_main_callback(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 0
+ if (status == kStatus_DSPI_Error)
+ {
+ __NOP();
+ }
+#endif
+ portYIELD_FROM_ISR(reschedule);
+}
+
+static void SPI_callback(SPI_Type *base, dspi_slave_handle_t *handle, status_t status, void *userData)
+{
+ SPI_main_callback(status, userData);
+}
+
+static void SPI_EDMA_callback(SPI_Type *base, dspi_slave_edma_handle_t *handle, status_t status, void *userData)
+{
+ SPI_main_callback(status, userData);
+}
+
+static dspi_slave_config_t spi2_slaveConfig;
+
+static void SPI_init() {
+ gpio_pin_config_t gpio_out_config = {
+ kGPIO_DigitalOutput, 0,
+ };
+ GPIO_PinInit(GPIOD, 11u, &gpio_out_config);
+ /* Slave config */
+ spi2_slaveConfig.whichCtar = kDSPI_Ctar0;
+ spi2_slaveConfig.ctarConfig.bitsPerFrame = 8;
+ spi2_slaveConfig.ctarConfig.cpol = kDSPI_ClockPolarityActiveHigh;
+ spi2_slaveConfig.ctarConfig.cpha = kDSPI_ClockPhaseSecondEdge;
+ spi2_slaveConfig.enableContinuousSCK = false;
+ spi2_slaveConfig.enableRxFifoOverWrite = true;
+ spi2_slaveConfig.enableModifiedTimingFormat = false;
+ spi2_slaveConfig.samplePoint = kDSPI_SckToSin0Clock;
+ PRINTF("SPI init \r\n");
+ DSPI_SlaveInit(SPI2, &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 spi_msg;
+ dspi_transfer_t slaveXfer;
+ int ret = 0;
+ int can_read = -1;
+#ifdef SPI_DMA
+ uint32_t slaveRxChannel, slaveTxChannel;
+ edma_config_t userConfig;
+#endif
+
+ spi_msg.sem = xSemaphoreCreateBinary();
+ spi_handle.userData = &spi_msg;
+ SPI_init();
+#ifdef SPI_DMA
+ slaveRxChannel = 0U;
+ slaveTxChannel = 1U;
+
+ DMAMUX_Init(DMAMUX);
+ DMAMUX_SetSource(DMAMUX, slaveRxChannel, kDmaRequestMux0SPI2Rx);
+ DMAMUX_EnableChannel(DMAMUX, slaveRxChannel);
+ DMAMUX_SetSource(DMAMUX, slaveTxChannel, kDmaRequestMux0SPI2Tx);
+ DMAMUX_EnableChannel(DMAMUX, slaveTxChannel);
+
+ EDMA_GetDefaultConfig(&userConfig);
+ EDMA_Init(DMA0, &userConfig);
+
+ EDMA_CreateHandle(&dspiEdmaSlaveRxHandle, DMA0, slaveRxChannel);
+ EDMA_CreateHandle(&dspiEdmaSlaveTxHandle, DMA0, slaveTxChannel);
+
+ g_dspi_edma_s_handle.userData = &spi_msg;
+ DSPI_SlaveTransferCreateHandleEDMA(SPI2, &g_dspi_edma_s_handle, SPI_EDMA_callback,
+ &spi_msg, &dspiEdmaSlaveRxHandle, &dspiEdmaSlaveTxHandle);
+#endif
+ memset((uint8_t *)registers, 0x00, APALIS_TK1_K20_LAST_REG);
+ registers[APALIS_TK1_K20_REVREG] = APALIS_TK1_K20_FW_VER;
+ GPIO_SetPinsOutput(GPIOA, 1u << 29u); /* INT2 idle */
+ slaveXfer.configFlags = kDSPI_SlaveCtar0;
+
+ while(1){
+ slaveXfer.txData = NULL;/* no MISO traffic*/
+ slaveXfer.rxData = slaveRxData;
+ slaveXfer.dataSize = 3;
+ /* Wait for instructions from SoC */
+ ret = DSPI_SlaveTransferNonBlocking(SPI2, &spi_handle, &slaveXfer);
+ if ( ret == kStatus_Success) {
+ xSemaphoreTake(spi_msg.sem, portMAX_DELAY);
+
+ if (slaveRxData[0] != APALIS_TK1_K20_READ_INST) {
+ taskENTER_CRITICAL();
+ slaveXfer.txData = slaveTxData;
+ slaveXfer.rxData = slaveRxData;
+ if (slaveRxData[1] <= 0x05) {
+ ret = general_registers(&slaveXfer);
+#ifndef TESTER_BUILD
+ } else if ((slaveRxData[1] >= APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(0))
+ && (slaveRxData[1] <= APALIS_TK1_K20_CAN_OUT_BUF_END + APALIS_TK1_K20_CAN_DEV_OFFSET(0))) {
+ ret = canx_registers(&slaveXfer, 0);
+ can_read = 0;
+
+ } else if ((slaveRxData[1] >= APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(1))
+ && (slaveRxData[1] <= APALIS_TK1_K20_CAN_OUT_BUF_END + APALIS_TK1_K20_CAN_DEV_OFFSET(1))) {
+ ret = canx_registers(&slaveXfer, 1);
+ can_read = 1;
+#endif
+#ifdef BOARD_USES_ADC
+ } else if ((slaveRxData[1] >= APALIS_TK1_K20_ADCREG) && (slaveRxData[1] <= APALIS_TK1_K20_ADC_CH3H)) {
+ ret = adc_registers(&slaveXfer);
+
+ } else if ((slaveRxData[1] >= APALIS_TK1_K20_TSCREG) && (slaveRxData[1] <= APALIS_TK1_K20_TSC_YPH)) {
+ ret = tsc_registers(&slaveXfer);
+#endif
+ } else if ((slaveRxData[1] >= APALIS_TK1_K20_GPIOREG) && (slaveRxData[1] <= APALIS_TK1_K20_GPIO_STA)) {
+ ret = gpio_registers(&slaveXfer);
+ } else {
+ /* Register not defined */
+ ret = -EINVAL;
+ }
+
+ if (ret < 0) {
+ PRINTF("Invalid read/write ret = %d rx[0] = 0x%x, rx[1] = 0x%x, rx[2] = 0x%x\r\n",
+ ret, slaveRxData[0], slaveRxData[1], slaveRxData[2]);
+ }
+
+ if (slaveRxData[0] == APALIS_TK1_K20_BULK_READ_INST) {
+ slaveXfer.dataSize = ret;
+ slaveXfer.rxData = NULL;
+#ifdef SPI_DMA
+ DSPI_SlaveTransferEDMA(SPI2, &g_dspi_edma_s_handle, &slaveXfer);
+#else
+ DSPI_SlaveTransferNonBlocking(SPI2, &spi_handle, &slaveXfer);
+#endif
+ taskEXIT_CRITICAL();
+ xSemaphoreTake(spi_msg.sem, portMAX_DELAY);
+
+ if (can_read >= 0) {
+ can_spi_read_complete(can_read);
+ can_read = -1;
+ }
+ } else {
+ taskEXIT_CRITICAL();
+ }
+ }
+ } else {
+ /* Something went wrong, retry */
+ DSPI_SlaveTransferAbort(SPI2, &spi_handle);
+ }
+ }
+}
diff --git a/app/src/gpio_ext.c b/app/src/gpio_ext.c
new file mode 100644
index 0000000..e0d55fb
--- /dev/null
+++ b/app/src/gpio_ext.c
@@ -0,0 +1,132 @@
+/*
+ * gpio_ext.c
+ *
+ */
+
+#include "gpio_ext.h"
+#include "com_task.h"
+#include "errno.h"
+
+extern const struct gpio_id *gpio_list;
+
+
+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.
+ */
+static 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;
+ }
+ if (temp > pin)
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+static int set_gpio_status(uint8_t status, int index)
+{
+ gpio_pin_config_t gpio_config;
+
+ gpio_config.pinDirection = (status & APALIS_TK1_K20_GPIO_STA_OE) ? kGPIO_DigitalOutput : kGPIO_DigitalInput;
+ gpio_config.outputLogic = (status & APALIS_TK1_K20_GPIO_STA_VAL);
+
+ if (index >= 0)
+ GPIO_PinInit(gpio_list[index].gpio, gpio_list[index].pin, &gpio_config);
+ else
+ return index;
+
+ return 0;
+}
+
+
+static uint8_t get_gpio_status(int index)
+{
+ uint8_t status;
+ GPIO_Type *base;
+ uint32_t gpio_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(dspi_transfer_t *spi_transfer)
+{
+ uint8_t *rx_buf = spi_transfer->rxData;
+ int index;
+
+ 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:
+ index = is_gpio_valid(rx_buf[2]);
+ if (index >= 0){
+ registers[APALIS_TK1_K20_GPIO_NO]= rx_buf[2];
+ registers[APALIS_TK1_K20_GPIO_STA] = get_gpio_status(index);
+ return 1;
+ } else {
+ registers[APALIS_TK1_K20_GPIO_NO] = 0xFF;
+ return -ENOENT;
+ }
+ break;
+ case APALIS_TK1_K20_GPIO_STA:
+ index = is_gpio_valid(registers[APALIS_TK1_K20_GPIO_NO]);
+ if (index >= 0){
+ set_gpio_status(rx_buf[2], index);
+ registers[APALIS_TK1_K20_GPIO_STA] = get_gpio_status(index);
+ return 1;
+ } else {
+ return -ENOENT;
+ }
+ break;
+ default:
+ return -ENOENT;
+ }
+ }
+ return -ENOENT;
+}
+
+
+
+
diff --git a/app/src/main.c b/app/src/main.c
new file mode 100644
index 0000000..1c36984
--- /dev/null
+++ b/app/src/main.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013 - 2016, Freescale Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * This is template for main module created by New Kinetis SDK 2.x Project Wizard. Enjoy!
+ **/
+
+#include <string.h>
+
+#include "board.h"
+#include "pin_mux.h"
+#include "clock_config.h"
+#include "fsl_debug_console.h"
+#include "com_task.h"
+#include "can_task.h"
+#include "adc_task.h"
+
+/* FreeRTOS kernel includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#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
+
+#ifdef BOARD_USES_ADC
+TaskHandle_t adc_task_handle;
+TaskHandle_t tsc_task_handle;
+#endif
+#ifndef TESTER_BUILD
+TaskHandle_t can0_task_handle;
+TaskHandle_t can1_task_handle;
+TaskHandle_t can_tx_notify_task_handle;
+#endif
+TaskHandle_t spi_task_handle;
+
+
+/*!
+ * @brief Application entry point.
+ */
+int main(void) {
+
+ /* Init board hardware. */
+ BOARD_InitPins();
+ BOARD_BootClockRUN();
+#ifndef TESTER_BUILD
+ BOARD_InitDebugConsole();
+#endif
+ PRINTF("Apalis K20 Firmware Version %d.%d\r\n", FW_MAJOR, FW_MINOR);
+
+ /* Create RTOS task */
+ if(xTaskCreate(spi_task, "SPI_task", 1000L / sizeof(portSTACK_TYPE), NULL, 4, &spi_task_handle) != pdPASS)
+ {
+ PRINTF("create SPI task error\r\n");
+ }
+#ifndef TESTER_BUILD
+ if(xTaskCreate(can0_task, "CAN0_task", 1000L / sizeof(portSTACK_TYPE), NULL, 2, &can0_task_handle) != pdPASS)
+ {
+ PRINTF("create CAN0 task error\r\n");
+ }
+
+ if(xTaskCreate(can1_task, "CAN1_task", 1000L / sizeof(portSTACK_TYPE), NULL, 2, &can1_task_handle) != pdPASS)
+ {
+ PRINTF("create CAN1 task error\r\n");
+ }
+
+ if(xTaskCreate(can_tx_notify_task, "CAN_tx_notify_task", 1000L / sizeof(portSTACK_TYPE), NULL, 3, &can_tx_notify_task_handle) != pdPASS)
+ {
+ PRINTF("create CAN TX notify task error\r\n");
+ }
+#endif
+#ifdef BOARD_USES_ADC
+ if(xTaskCreate(adc_task, "ADC_task", 1000L / sizeof(portSTACK_TYPE), NULL, 2, &adc_task_handle) != pdPASS)
+ {
+ PRINTF("create ADC task error\r\n");
+ }
+
+ if(xTaskCreate(tsc_task, "TSC_task", 1000L / sizeof(portSTACK_TYPE), NULL, 2, &tsc_task_handle) != pdPASS)
+ {
+ PRINTF("create TSC task error\r\n");
+ }
+#endif
+
+ NVIC_SetPriority(CAN0_ORed_Message_buffer_IRQn, 7u);
+ NVIC_SetPriority(CAN0_Bus_Off_IRQn, 8u);
+ NVIC_SetPriority(CAN0_Error_IRQn, 8u);
+ NVIC_SetPriority(CAN0_Tx_Warning_IRQn, 8u);
+ NVIC_SetPriority(CAN0_Rx_Warning_IRQn, 8u);
+ NVIC_SetPriority(CAN0_Wake_Up_IRQn, 8u);
+ NVIC_SetPriority(CAN1_ORed_Message_buffer_IRQn, 7u);
+ NVIC_SetPriority(CAN1_Bus_Off_IRQn, 8u);
+ NVIC_SetPriority(CAN1_Error_IRQn, 8u);
+ NVIC_SetPriority(CAN1_Tx_Warning_IRQn, 8u);
+ NVIC_SetPriority(CAN1_Rx_Warning_IRQn, 8u);
+ NVIC_SetPriority(CAN1_Wake_Up_IRQn, 8u);
+ NVIC_SetPriority(SPI2_IRQn, 5u);
+ NVIC_SetPriority(DMA0_IRQn, 6u);
+ vTaskStartScheduler();
+
+ for(;;) { /* Infinite loop to avoid leaving the main function */
+ __asm("NOP"); /* something to use as a breakpoint stop while looping */
+ }
+}
+
+
+