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
|
||||
/.mxproject
|
||||
/.vscode
|
||||
/.vscode
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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) {
|
||||
// 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();
|
||||
|
||||
|
|
|
@ -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