Added PN512 skeleton and SVD file.

This commit is contained in:
imi415 2022-02-22 21:46:03 +08:00
parent 45105dd51b
commit fbc8ddefd4
Signed by: imi415
GPG Key ID: 17F01E106F9F5E0A
8 changed files with 38426 additions and 6 deletions

2
.gitignore vendored
View File

@ -3,4 +3,4 @@
/lib/mruby/build_config.rb.lock
/lib/mruby/build
/.mxproject
/.vscode
/.vscode

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.10)
project(NUC200_Template)
project(NUC200LE3AN_Card)
enable_language(CXX)
enable_language(ASM)
@ -39,6 +39,7 @@ set(TARGET_C_SOURCES
"BSP/StdDriver/src/wdt.c"
"BSP/StdDriver/src/wwdt.c"
"src/main.c"
"src/nfc_impl.c"
)
# Copy them from Makefile
@ -61,6 +62,7 @@ set(TARGET_C_INCLUDES
# Shared libraries linked with application
set(TARGET_LIBS
"smartcard"
"pn512"
"freertos_kernel"
)
@ -96,6 +98,7 @@ set(FREERTOS_HEAP "4" CACHE STRING "")
set(FREERTOS_CONFIG_FILE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include" CACHE STRING "")
add_subdirectory(lib/FreeRTOS-Kernel)
add_subdirectory(lib/pn512)
# Shared sources, includes and definitions
add_compile_definitions(${TARGET_C_DEFINES})
include_directories(${TARGET_C_INCLUDES})

14
lib/pn512/CMakeLists.txt Normal file
View File

@ -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})

45
lib/pn512/include/pn512.h Normal file
View File

@ -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

113
lib/pn512/src/pn512.c Normal file
View File

@ -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;
}

38164
misc/NUC200AN_v1.svd Normal file

File diff suppressed because it is too large Load Diff

View File

@ -78,13 +78,14 @@ static void system_clock_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) {
GPIO_SetMode(PA, BIT3, GPIO_PMD_OPEN_DRAIN);
PA->DOUT ^= BIT4;
for(;;) {
PA->DOUT ^= BIT3;
PA->DOUT ^= BIT3 | BIT4;
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
@ -93,7 +94,7 @@ int main(int argc, const char *argv[]) {
system_clock_config();
pinmux_config();
xTaskCreate(hello_task, "HELLO", 128, NULL, 5, NULL);
xTaskCreate(hello_task, "HELLO", 128, NULL, 6, NULL);
vTaskStartScheduler();

80
src/nfc_impl.c Normal file
View File

@ -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 */
}