generated from Embedded_Projects/NUC200_Template
Added PN512 skeleton and SVD file.
This commit is contained in:
parent
45105dd51b
commit
fbc8ddefd4
|
@ -3,4 +3,4 @@
|
||||||
/lib/mruby/build_config.rb.lock
|
/lib/mruby/build_config.rb.lock
|
||||||
/lib/mruby/build
|
/lib/mruby/build
|
||||||
/.mxproject
|
/.mxproject
|
||||||
/.vscode
|
/.vscode
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
project(NUC200_Template)
|
project(NUC200LE3AN_Card)
|
||||||
|
|
||||||
enable_language(CXX)
|
enable_language(CXX)
|
||||||
enable_language(ASM)
|
enable_language(ASM)
|
||||||
|
@ -39,6 +39,7 @@ set(TARGET_C_SOURCES
|
||||||
"BSP/StdDriver/src/wdt.c"
|
"BSP/StdDriver/src/wdt.c"
|
||||||
"BSP/StdDriver/src/wwdt.c"
|
"BSP/StdDriver/src/wwdt.c"
|
||||||
"src/main.c"
|
"src/main.c"
|
||||||
|
"src/nfc_impl.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Copy them from Makefile
|
# Copy them from Makefile
|
||||||
|
@ -61,6 +62,7 @@ set(TARGET_C_INCLUDES
|
||||||
# Shared libraries linked with application
|
# Shared libraries linked with application
|
||||||
set(TARGET_LIBS
|
set(TARGET_LIBS
|
||||||
"smartcard"
|
"smartcard"
|
||||||
|
"pn512"
|
||||||
"freertos_kernel"
|
"freertos_kernel"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -96,6 +98,7 @@ set(FREERTOS_HEAP "4" CACHE STRING "")
|
||||||
set(FREERTOS_CONFIG_FILE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include" CACHE STRING "")
|
set(FREERTOS_CONFIG_FILE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include" CACHE STRING "")
|
||||||
add_subdirectory(lib/FreeRTOS-Kernel)
|
add_subdirectory(lib/FreeRTOS-Kernel)
|
||||||
|
|
||||||
|
add_subdirectory(lib/pn512)
|
||||||
# Shared sources, includes and definitions
|
# Shared sources, includes and definitions
|
||||||
add_compile_definitions(${TARGET_C_DEFINES})
|
add_compile_definitions(${TARGET_C_DEFINES})
|
||||||
include_directories(${TARGET_C_INCLUDES})
|
include_directories(${TARGET_C_INCLUDES})
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
project(pn512)
|
||||||
|
|
||||||
|
set(PN512_SOURCES
|
||||||
|
"src/pn512.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(PN512_INCLUDES
|
||||||
|
"include"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME} ${PN512_SOURCES})
|
||||||
|
target_include_directories(${PROJECT_NAME} PUBLIC ${PN512_INCLUDES})
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef PN512_H
|
||||||
|
#define PN512_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef enum pn512_ret {
|
||||||
|
PN512_OK,
|
||||||
|
PN512_FAIL,
|
||||||
|
} pn512_ret_t;
|
||||||
|
|
||||||
|
typedef pn512_ret_t (*pn512_read_ops_t)(void *handle, uint8_t reg, uint8_t *data, uint16_t len);
|
||||||
|
typedef pn512_ret_t (*pn512_write_ops_t)(void *handle, uint8_t reg, uint8_t *data, uint16_t len);
|
||||||
|
typedef pn512_ret_t (*pn512_poll_irq_ops_t)(void *handle, uint32_t max_timeout);
|
||||||
|
typedef pn512_ret_t (*pn512_delay_ops_t)(void *handle, uint32_t msec);
|
||||||
|
typedef pn512_ret_t (*pn512_reset_ops_t)(void *handle);
|
||||||
|
|
||||||
|
typedef struct pn512_if_ops {
|
||||||
|
pn512_read_ops_t read;
|
||||||
|
pn512_write_ops_t write;
|
||||||
|
pn512_poll_irq_ops_t poll_irq;
|
||||||
|
pn512_delay_ops_t delay;
|
||||||
|
pn512_reset_ops_t reset;
|
||||||
|
} pn512_if_ops_t;
|
||||||
|
|
||||||
|
typedef struct pn512_app_cb {
|
||||||
|
} pn512_app_cb_t;
|
||||||
|
|
||||||
|
typedef struct pn512_info {
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t current_page;
|
||||||
|
} pn512_info_t;
|
||||||
|
|
||||||
|
typedef struct pn512 {
|
||||||
|
pn512_if_ops_t ops;
|
||||||
|
void *ops_handle;
|
||||||
|
|
||||||
|
pn512_app_cb_t cb;
|
||||||
|
void *cb_data;
|
||||||
|
|
||||||
|
pn512_info_t info;
|
||||||
|
} pn512_t;
|
||||||
|
|
||||||
|
pn512_ret_t pn512_init(pn512_t *nfc);
|
||||||
|
|
||||||
|
#endif // PN512_H
|
|
@ -0,0 +1,113 @@
|
||||||
|
#include "pn512.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* About register bits
|
||||||
|
* Higher 8 bits is page number, e.g. 0x8100 -> Page 1 addr 0
|
||||||
|
* Bit 15 is always 1 since we use page select.
|
||||||
|
*/
|
||||||
|
#define PN512_REG_COMMAND 0x8001U
|
||||||
|
#define PN512_REG_PAGE_SELECT 0x8000U
|
||||||
|
#define PN512_REG_VERSION 0x8337U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command List
|
||||||
|
*/
|
||||||
|
#define PN512_CMD_SOFT_RESET 0x0F
|
||||||
|
|
||||||
|
#define PN512_REG_PAGE(x) ((uint8_t)(x >> 0x08U))
|
||||||
|
#define PN512_REG_ADDR(x) ((uint8_t)(x & 0xFFU))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Switch register page to the same page as
|
||||||
|
* specified by `reg`.
|
||||||
|
*
|
||||||
|
* @param nfc: pointer to pn512_t struct
|
||||||
|
* @param reg: 16bit register to be set, `PN512_REG_XXXX`
|
||||||
|
* @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error.
|
||||||
|
*/
|
||||||
|
static pn512_ret_t pn512_switch_register_page(pn512_t *nfc, uint16_t reg) {
|
||||||
|
pn512_ret_t ret = PN512_OK;
|
||||||
|
|
||||||
|
if (PN512_REG_PAGE(reg) != nfc->info.current_page) {
|
||||||
|
/* Select page */
|
||||||
|
uint8_t payload = PN512_REG_PAGE(reg);
|
||||||
|
ret = nfc->ops.write(nfc->ops_handle, PN512_REG_ADDR(PN512_REG_PAGE_SELECT), &payload, 1U);
|
||||||
|
if (ret != PN512_OK) return ret;
|
||||||
|
|
||||||
|
nfc->info.current_page = PN512_REG_PAGE(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a register, except FIFO register.
|
||||||
|
*
|
||||||
|
* @param nfc: pointer to pn512_t struct
|
||||||
|
* @param reg: 16bit register to be set, `PN512_REG_XXXX`
|
||||||
|
* @param value: [OUT] value to be read
|
||||||
|
* @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error.
|
||||||
|
*/
|
||||||
|
static pn512_ret_t pn512_read_register(pn512_t *nfc, uint16_t reg, uint8_t *value) {
|
||||||
|
pn512_ret_t ret = PN512_OK;
|
||||||
|
|
||||||
|
ret = pn512_switch_register_page(nfc, reg);
|
||||||
|
if (ret != PN512_OK) return ret;
|
||||||
|
|
||||||
|
/* Issue read operation */
|
||||||
|
ret = nfc->ops.read(nfc->ops_handle, PN512_REG_ADDR(reg), value, 1U);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a register, except FIFO register.
|
||||||
|
*
|
||||||
|
* @param nfc: pointer to pn512_t struct
|
||||||
|
* @param reg: 16bit register to be set, `PN512_REG_XXXX`
|
||||||
|
* @param value: value to be written
|
||||||
|
* @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error.
|
||||||
|
*/
|
||||||
|
static pn512_ret_t pn512_write_register(pn512_t *nfc, uint16_t reg, uint8_t value) {
|
||||||
|
pn512_ret_t ret = PN512_OK;
|
||||||
|
|
||||||
|
ret = pn512_switch_register_page(nfc, reg);
|
||||||
|
if (ret != PN512_OK) return ret;
|
||||||
|
|
||||||
|
/* Issue read operation */
|
||||||
|
ret = nfc->ops.write(nfc->ops_handle, PN512_REG_ADDR(reg), &value, 1U);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Soft reset PN512 by sending an SoftReset command.
|
||||||
|
*
|
||||||
|
* @param nfc: pointer to pn512_t struct
|
||||||
|
* @return pn512_ret_t: PN512_OK for success, PN512_FAIL for error.
|
||||||
|
*/
|
||||||
|
static pn512_ret_t pn512_soft_reset(pn512_t *nfc) {
|
||||||
|
return pn512_write_register(nfc, PN512_REG_COMMAND, PN512_CMD_SOFT_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
pn512_ret_t pn512_init(pn512_t *nfc) {
|
||||||
|
pn512_ret_t ret = PN512_OK;
|
||||||
|
|
||||||
|
/* Reset chip */
|
||||||
|
ret = nfc->ops.reset(nfc->ops_handle);
|
||||||
|
if (ret != PN512_OK) return ret;
|
||||||
|
|
||||||
|
/* Set current page to 0 */
|
||||||
|
uint8_t payload = 0x80;
|
||||||
|
ret = nfc->ops.write(nfc->ops_handle, PN512_REG_ADDR(PN512_REG_PAGE_SELECT), &payload, 1U);
|
||||||
|
if (ret != PN512_OK) return ret;
|
||||||
|
|
||||||
|
nfc->info.current_page = 0; /* Synchronize status */
|
||||||
|
|
||||||
|
ret = pn512_soft_reset(nfc);
|
||||||
|
if (ret != PN512_OK) return ret;
|
||||||
|
|
||||||
|
// Read chip version.
|
||||||
|
ret = pn512_read_register(nfc, PN512_REG_VERSION, &nfc->info.version);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -78,13 +78,14 @@ static void system_clock_config(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pinmux_config(void) {
|
static void pinmux_config(void) {
|
||||||
// Nothing for now.
|
GPIO_SetMode(PA, BIT3, GPIO_PMD_OPEN_DRAIN); /* LED_GREEN */
|
||||||
|
GPIO_SetMode(PA, BIT4, GPIO_PMD_OPEN_DRAIN); /* LED_RED */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hello_task(void *pvParameters) {
|
static void hello_task(void *pvParameters) {
|
||||||
GPIO_SetMode(PA, BIT3, GPIO_PMD_OPEN_DRAIN);
|
PA->DOUT ^= BIT4;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
PA->DOUT ^= BIT3;
|
PA->DOUT ^= BIT3 | BIT4;
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +94,7 @@ int main(int argc, const char *argv[]) {
|
||||||
system_clock_config();
|
system_clock_config();
|
||||||
pinmux_config();
|
pinmux_config();
|
||||||
|
|
||||||
xTaskCreate(hello_task, "HELLO", 128, NULL, 5, NULL);
|
xTaskCreate(hello_task, "HELLO", 128, NULL, 6, NULL);
|
||||||
|
|
||||||
vTaskStartScheduler();
|
vTaskStartScheduler();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "NUC200Series.h"
|
||||||
|
#include "pn512.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
#define NFC_RESET_GPIO PA
|
||||||
|
#define NFC_RESET_PIN BIT15
|
||||||
|
|
||||||
|
/* PN512 has a strange SPI timing, see DS § 9.2 */
|
||||||
|
/* **Stop it, Get some help.** */
|
||||||
|
|
||||||
|
pn512_ret_t nfc_impl_reset_ops(void *handle) {
|
||||||
|
/* Clear nRSTPD */
|
||||||
|
NFC_RESET_GPIO->DOUT &= ~(NFC_RESET_PIN);
|
||||||
|
|
||||||
|
/* ..Sleep for a while */
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(5));
|
||||||
|
|
||||||
|
/* Set nRSTPD */
|
||||||
|
NFC_RESET_GPIO->DOUT |= NFC_RESET_PIN;
|
||||||
|
|
||||||
|
return PN512_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
pn512_ret_t nfc_impl_delay_ops(void *handle, uint32_t msec) {
|
||||||
|
/* .. */
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(msec));
|
||||||
|
|
||||||
|
return PN512_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
pn512_ret_t nfc_impl_read_ops(void *handle, uint8_t reg, uint8_t *data, uint16_t len) {
|
||||||
|
/*
|
||||||
|
* SPI Read sequence(len + 1 bytes in total):
|
||||||
|
* CS->LOW
|
||||||
|
* MOSI send 1st address byte, ignore MISO data.
|
||||||
|
* MISO receive `len` bytes, while MOSI repeats 1st byte data.
|
||||||
|
* CS->HIGH
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* .. */
|
||||||
|
|
||||||
|
return PN512_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
pn512_ret_t nfc_impl_write_ops(void *handle, uint8_t reg, uint8_t *data, uint16_t len) {
|
||||||
|
/*
|
||||||
|
* SPI Write sequence(len + 1 bytes in total):
|
||||||
|
* CS->LOW
|
||||||
|
* MOSI send 1st address byte, data payload follows.
|
||||||
|
* CS->HIGH
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* .. */
|
||||||
|
|
||||||
|
return PN512_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
pn512_ret_t pn512_poll_irq_ops(void *handle, uint32_t max_timeout) {
|
||||||
|
/*
|
||||||
|
* Poll for GPIO interrupt
|
||||||
|
* (Get Semaphore)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* .. */
|
||||||
|
|
||||||
|
return PN512_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* <-- SPI0_IRQHandler --> */
|
||||||
|
void SPI0_IRQHandler(void) {
|
||||||
|
/* DMA or FIFO xfer flags. */
|
||||||
|
/* .. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* <-- EXTI --> */
|
||||||
|
void GPAB_IRQHandler(void) {
|
||||||
|
/* ??? Sasuga Nuvoton */
|
||||||
|
}
|
Loading…
Reference in New Issue