ATECC508A芯片开发笔记(十一):NXP 平台移植ATECCx08 CryptoAuthLib库(I2C)



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
    : 目录结构

该软件库的说明文档还是写的比较清楚的,其目录 结构如下:
Lib库结构


二、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系列:

网络安全系列:

嵌入式开发系列:

AI / 机器学习系列:


在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HowieXue

求打赏~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值