目录
ATECC508A芯片开发笔记(十一):NXP 平台移植x08库(I2C)
- CryptoAuthLib最新库
- Nxp RT10xx平台上移植CryptoAuthLib
- 驱动代码分析
硬件环境: Nxp的i.Mx RT1060 MCU
软件环境: cryptoauthlib-20190903 (MicroChip官网下载)
之前在Nxp平台上使用过ATECC608A,所以将CryptoAuthLib移植后的代码分享出来。。
最近太忙,好久没有写博客了,刚发现ATECCx08系列都写到第十一啦。。。。
一、CryptoAuthLib
概述
Atmel CryptoAuthentication Library是Atmel 兼容其加密芯片系列一个总的软件库,里面实现了从底层到命令层以及应用层开发使用的所有API,并支持Git使用。
该库还在不断完善,兼容Atmel许多开发板,目前能够support的加密芯片有:
- ATECCx08A (ATECC108A, ATECC508A, ATECC608A)
- ATSHA204A
- ATAES132A
: 目录结构
该软件库的说明文档还是写的比较清楚的,其目录 结构如下:
二、Nxp RT10xx平台上移植CryptoAuthLib
基础知识可以参见之前的博客:
ATECC508A芯片开发笔记(二):开发准备之 CryptoAuthLib 库简介与移植
2.1、在官网下载最新的CryptoAuthLib库:
https://www.microchip.com/wwwproducts/en/ATECC608A
2.2、将\lib\hal中无用的代码去掉,并新建自己Driver的.c/h
参见 ATECC508A芯片开发笔记(二):开发准备之 CryptoAuthLib 库简介与移植
2.3、根据Nxp平台实现初始化、收发等函数:
- hal_i2c_init:
ATCA_STATUS hal_i2c_init(void *hal, ATCAIfaceCfg *cfg)
{
hal_i2c_log("ini i2c\r\n");
/* BEGIN: Added by Howard Xue, 2018/10/28 */
lpi2c_master_config_t masterConfig = {0};
// LPI2C_MasterGetDefaultConfig(&lpi2cConfig);
masterConfig.enableMaster = true;
masterConfig.debugEnable = false;
masterConfig.enableDoze = true;
masterConfig.ignoreAck = true;
masterConfig.pinConfig = kLPI2C_2PinOpenDrain;
masterConfig.baudRate_Hz = 400000U;
masterConfig.busIdleTimeout_ns = 0;
masterConfig.pinLowTimeout_ns = 0;
masterConfig.sdaGlitchFilterWidth_ns = 0;
masterConfig.sclGlitchFilterWidth_ns = 0;
masterConfig.hostRequest.enable = false;
masterConfig.hostRequest.source = kLPI2C_HostRequestExternalPin;
masterConfig.hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh;
LPI2C_MasterInit(ATECC608_LPI2C_BASEADDR, &masterConfig, LPI2C_CLOCK_FREQUENCY);
return ATCA_SUCCESS;
}
- hal_i2c_send:
ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength)
{
hal_i2c_log("send i2c\r\n");
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
status_t reVal;
// txdata[0] is using _reserved byte of the ATCAPacket
txdata[0] = 0x03; // insert the Word Address Value, Command token
txlength++; // account for word address value byte.
lpi2c_master_transfer_t transfer;
transfer.flags = kLPI2C_TransferDefaultFlag;
transfer.slaveAddress = (cfg->atcai2c.slave_address);
transfer.direction = kLPI2C_Write;
transfer.subaddress = 0;
transfer.subaddressSize = 0;
transfer.data = txdata;
transfer.dataSize = txlength;
reVal = LPI2C_MasterTransferBlocking(ATECC608_LPI2C_BASEADDR, &transfer);
return reVal;
hal_i2c_log("send i2c ok\r\n");
return ATCA_SUCCESS;
}
- hal_i2c_receive:
ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength)
{
hal_i2c_log("recv i2c\r\n");
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
/* BEGIN: Added by Howard Xue, 2018/10/28 */
status_t reVal;
lpi2c_master_transfer_t transfer;
transfer.flags = kLPI2C_TransferDefaultFlag;
transfer.slaveAddress = (cfg->atcai2c.slave_address);
transfer.direction = kLPI2C_Read;
transfer.subaddress = 0;
transfer.subaddressSize = 0;
transfer.data = rxdata;
transfer.dataSize = *rxlength;
LPI2C_MasterTransferBlocking(ATECC608_LPI2C_BASEADDR, &transfer);
hal_i2c_log("recv i2c ok\r\n");
return ATCA_SUCCESS;
}
- hal_i2c_wake
/** \brief wake up CryptoAuth device using I2C bus
* \param[in] iface interface to logical device to wakeup
* \return ATCA_SUCCESS on success, otherwise an error code.
*/
ATCA_STATUS hal_i2c_wake(ATCAIface iface)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
uint8_t address = cfg->atcai2c.slave_address;
uint32_t bdrt = cfg->atcai2c.baud;
uint8_t data[4], expected[4] = { 0x04, 0x11, 0x33, 0x43 };
uint8_t dummy_byte = 0x00;
if (bdrt >= 400000) //Howard : if not already at 100KHz, change it to 100K for wake sequence
{
change_i2c_speed(iface, 100000);
}
// Send the wake by writing to an address of 0x00
// Create wake up pulse by sending a slave address 0f 0x00.
// This slave address is sent to device by using a dummy write command.
// Dummy Write
// This command will always return NACK.
// So, the return code is being ignored.
hal_i2c_send(ATECC_LPI2C_BASEADDR, 0, &dummy_byte, 1);
hal_i2c_abort(ATECC_LPI2C_BASEADDR);
// if necessary, revert baud rate to what came in.
if (bdrt >= 400000)
{
change_i2c_speed(iface, bdrt);
}
atca_delay_us(cfg->wake_delay); // Howard: wait tWHI + tWLO which is configured based on device type and configuration structure
status_t err_code = hal_i2c_receive(ATECC_LPI2C_BASEADDR, address, data, 4);
if (err_code != kStatus_Success)
{
return ATCA_RX_NO_RESPONSE;
}
// compared with fixed wakeup data.
if (memcmp(data, expected, 4) == 0)
{
return ATCA_SUCCESS;
}
return ATCA_COMM_FAIL;
}
- 延时函数 (基于FreeRTOS):
#define AT608_DELAY_CPU_FREQ_CYCLE (60)
#define AT608_FREERTOS (1)
void hardware_delay_us(uint32_t us)
{
volatile uint32_t i = 0;
if(us == 0)
return;
for (i = 0; i < us*AT608_DELAY_CPU_FREQ_CYCLE; ++i)
{
__asm("NOP"); /* delay */
}
}
/**
* \brief This function delays for a number of microseconds.
*
* \param[in] delay number of 0.001 milliseconds to delay
*/
void atca_delay_us(uint32_t delay)
{
/* BEGIN: Modified by Howard Xue, 2020/6/28 */
#ifdef AT608_FREERTOS
if(atecc_init)
vTaskDelay( 1 + (delay * (( ((uint64_t)configTICK_RATE_HZ) << 32 )/1000000) >> 32) );
else
hardware_delay_us( 1 + delay);
#else
hardware_delay_us( 1 + delay);
#endif
/* END: Modified by Howard Xue, 2020/6/28 PN: */
}
/**
* \brief This function delays for a number of milliseconds.
*
* You can override this function if you like to do
* something else in your system while delaying.
*
* \param[in] delay number of milliseconds to delay
*/
void atca_delay_ms(uint32_t delay)
{
#ifdef AT608_FREERTOS
if(atecc_init)
vTaskDelay( 1 + (delay * ((configTICK_RATE_HZ << 8)/1000) >> 8) );
else
hal_i2c_delay( 1 + delay*1000);
#else
hal_i2c_delay( 1 + delay*1000);
#endif
}
2.4、在atca_hal.h中打开I2C接口的宏开关
至此,移植工作就结束了,接下来可以对加密芯片硬件或CryptoAuthLib进行简单的测试,参照ATECC508A芯片开发笔记(二):开发准备之 CryptoAuthLib 库简介与移植
完整Driver代码下载地址:
https://download.csdn.net/download/HowieXue/11967660
三、驱动代码分析:
之前博文的代码分析,结构是一样的
第一层:
在atca_iface.c (libraries\cryptoauthlib\lib目录)中 ,有_atinit()这么一个函数,会在atcab_init初始化设备时调用,函数里实现了hal层通讯函数与API层的绑定:
ATCA_STATUS _atinit(ATCAIface caiface, ATCAHAL_t *hal)
{
// get method mapping to HAL methods for this interface
hal_iface_init( caiface->mIfaceCFG, hal );
caiface->atinit = hal->halinit;
caiface->atpostinit = hal->halpostinit;
caiface->atsend = hal->halsend;
caiface->atreceive = hal->halreceive;
caiface->atwake = hal->halwake;
caiface->atsleep = hal->halsleep;
caiface->atidle = hal->halidle;
caiface->hal_data = hal->hal_data;
return ATCA_SUCCESS;
}
第二层:
在atca_hal.c (libraries\cryptoauthlib\lib\hal) 中,实现了Hal层与底层通讯驱动函数的绑定,例如在前面我们打开了I2C宏: ATCA_I2C_IFACE,则现在hal层各函数就会与I2C相关函数绑定:
ATCA_STATUS hal_iface_init( ATCAIfaceCfg *cfg, ATCAHAL_t *hal )
{
ATCA_STATUS status = ATCA_COMM_FAIL;
switch (cfg->iface_type) {
case ATCA_I2C_IFACE:
#ifdef ATCA_HAL_I2C
hal->halinit = &hal_i2c_init;
hal->halpostinit = &hal_i2c_post_init;
hal->halreceive = &hal_i2c_receive;
hal->halsend = &hal_i2c_send;
hal->halsleep = &hal_i2c_sleep;
hal->halwake = &hal_i2c_wake;
hal->halidle = &hal_i2c_idle;
hal->halrelease = &hal_i2c_release;
hal->hal_data = NULL;
status = ATCA_SUCCESS;
#endif
break;
case ATCA_SWI_IFACE:
#ifdef ATCA_HAL_SWI...
第三层:
进入Hal_i2c_bitbang.c (libraries\cryptoauthlib\lib\hal),执行相应函数,比如上层通过atsend调用到了hal_i2c_send,就会执行该函数:该函数模拟了I2C通讯时序,(既先Start信号拉低SDA,之后发送7位地址位+1位读写,然后发送数据位、最后Stop信号拉高SDA),将一串数据发送到I2C总线。
ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
ATCA_STATUS status = ATCA_TX_TIMEOUT;
int bus = cfg->atcai2c.bus;
txdata[0] = 0x03; //!< Word Address Value = Command
txlength++; //!< count Word Address byte towards txlength
//! Set I2C pins
i2c_set_pin(i2c_hal_data[bus]->pin_sda, i2c_hal_data[bus]->pin_scl);
do {
//! Address the device and indicate that bytes are to be written
status = hal_i2c_send_slave_address(iface, I2C_WRITE);
if (status != ATCA_SUCCESS)
break;
//! Send the remaining bytes
status = i2c_send_bytes(txlength, txdata);
} while (0);
//! Send STOP regardless of i2c_status
i2c_send_stop();
return status;
}
支持原创,转载请附引用链接。
博主热门文章推荐:
一篇读懂系列:
LoRa Mesh系列:
网络安全系列:
- ATECC508A芯片开发笔记(一):初识加密芯片
- SHA/HMAC/AES-CBC/CTR 算法执行效率及RAM消耗 测试结果
- 常见加密/签名/哈希算法性能比较 (多平台 AES/DES, DH, ECDSA, RSA等)
- AES加解密效率测试(纯软件AES128/256)–以嵌入式Cortex-M0与M3 平台为例
嵌入式开发系列:
- 嵌入式学习中较好的练手项目和课题整理(附代码资料、学习视频和嵌入式学习规划)
- IAR调试使用技巧汇总:数据断点、CallStack、设置堆栈、查看栈使用和栈深度、Memory、Set Next Statement等
- Linux内核编译配置(Menuconfig)、制作文件系统 详细步骤
- Android底层调用C代码(JNI实现)
- 树莓派到手第一步:上电启动、安装中文字体、虚拟键盘、开启SSH等
- Android/Linux设备有线&无线 双网共存(同时上内、外网)
AI / 机器学习系列:
- AI: 机器学习必须懂的几个术语:Lable、Feature、Model…
- AI:卷积神经网络CNN 解决过拟合的方法 (Overcome Overfitting)
- AI: 什么是机器学习的数据清洗(Data Cleaning)
- AI: 机器学习的模型是如何训练的?(在试错中学习)
- 数据可视化:TensorboardX安装及使用(安装测试+实例演示)