因为我是在stm32上面做的加密操作,所以我只对stm32的方案做总结。

1.ATECC508的底层接口是i2c的,工程中跟i2c相关的操作放在文件hal_stm32l0_ateccx08_i2c.c中,文件应该放在cryptoauthlib\lib\hal\目录下。

2.Armel对这个库封装的比较深,分析下应用程序是如何调用底层的:

atecc508_init
  atcab_init( gIfaceCfg ) //这个全局变量很重要,底层的驱动结构体就是绑定在这个全局变量上,后面调用底层驱动,就直接调用这个指针了。
_gDevice = newATCADevice( cfg );
cadev->mIface = (ATCAIface)newATCAIface(cfg);
atinit(caiface)
_atinit( caiface, &hal );

可以看看_atinit(ATCAIface caiface, ATCAHAL_t *hal)这个函数:

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_STATUS hal_iface_init( ATCAIfaceCfg *cfg, ATCAHAL_t *hal )
{
// Because C isn't a real object oriented language or dynamically typed, some switch in the overall system is unavoidable
// The key here is to provide the flexibility to include just the types of interfaces you want/need without breaking the
// object model. The former is needed so in an embedded, constrained memory environment, you don't have to pay the price
// (in terms of memory) for interfaces you don't use in your application.
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; 。。。。。。。。。。。。

只截取了跟i2c相关的部分,清楚了函数的调用关系了吧。我们需要在hal_stm32l0_ateccx08_i2c.c里面实现这些函数:

ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
txdata[0] = 0x03; //!< Word Address Value = Command
txlength++; //!< count Word Address byte towards txlength uint32_t status = HAL_ERROR; do{
status = HAL_I2C_Master_Transmit(&hi2c1, ECC508_IIC_ADDRESS, txdata, txlength, ECC508_TX_TIMEOUT);
if(status != HAL_OK)
{
I2C_Reset();
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_STOPF); /* Clear STOP Flag */
I2C_RESET_CR2(&hi2c1); /* Clear Configuration Register 2 */
hi2c1.State = HAL_I2C_STATE_READY;
hi2c1.Mode = HAL_I2C_MODE_NONE;
__HAL_UNLOCK(&hi2c1); /* Process Unlocked */
hal_i2c_wake(iface);
}
}while(status != HAL_OK); return ATCA_SUCCESS; }
ATCA_STATUS hal_i2c_receive( ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength)
{
uint32_t status = HAL_ERROR; do{
status = HAL_I2C_Master_Receive(&hi2c1, ECC508_IIC_ADDRESS,rxdata,*rxlength,ECC508_RX_TIMEOUT);
if(status != HAL_OK)
{
I2C_Reset();
__HAL_I2C_CLEAR_FLAG(&hi2c1, I2C_FLAG_STOPF); /* Clear STOP Flag */
I2C_RESET_CR2(&hi2c1); /* Clear Configuration Register 2 */
hi2c1.State = HAL_I2C_STATE_READY;
hi2c1.Mode = HAL_I2C_MODE_NONE;
__HAL_UNLOCK(&hi2c1); /* Process Unlocked */
hal_i2c_wake(iface);
}
}while(status != HAL_OK); return ATCA_SUCCESS; }
ATCA_STATUS hal_i2c_wake(ATCAIface iface)
{
I2C_As_Normal_Gpio();
SCL_H;
SDA_L;
HAL_Delay(); /*86us*/
SDA_H;
HAL_Delay(); /*830us*/ // wait tWHI + tWLO which is configured based on device type and configuration structure
I2C_As_I2c_Gpio();
return ATCA_SUCCESS;
}

2.我遇到的问题:

1.延时函数,如上hal_i2c_wake里面有些延时函数,HAL_Delay()这个函数在ATECC508里面到处用到了,所以不同的芯片需要不同的实现,根本点就是要保证时间尽量准确。

2.遇到的最严重的问题还是stm32本身I2C的问题,设置的传输速率是400kbps,但是经常传着传着i2c就收不到数据了,这个在前面已经说过,没什么好说的。

我用普通io模拟了I2C,但是传输速率只能做到300kbps左右,再高上不去,虽然传输不存在问题,但是遇到了新的问题,看下面的函数,

ATCA_STATUS atcab_read_zone(uint8_t zone, uint8_t slot, uint8_t block, uint8_t offset, uint8_t *data, uint8_t len)
{
ATCA_STATUS status = ATCA_SUCCESS;
ATCAPacket packet;
uint16_t addr;
uint16_t execution_time = ; do {
// Check the input parameters
if (data == NULL)
return ATCA_BAD_PARAM; if ( len != && len != )
return ATCA_BAD_PARAM; // The get address function checks the remaining variables
if ( (status = atcab_get_addr(zone, slot, block, offset, &addr)) != ATCA_SUCCESS )
break; // If there are 32 bytes to write, then xor the bit into the mode
if (len == ATCA_BLOCK_SIZE)
zone = zone | ATCA_ZONE_READWRITE_32; // build a read command
packet.param1 = zone;
packet.param2 = addr; if ( (status = atRead( _gCommandObj, &packet )) != ATCA_SUCCESS )
break; execution_time = atGetExecTime( _gCommandObj, CMD_READMEM); if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) break; // send the command
if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS )
break; // delay the appropriate amount of time for command to execute
atca_delay_ms(execution_time); // receive the response
if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize) )) != ATCA_SUCCESS )
break;
// Check response size
if (packet.rxsize < ) {
if (packet.rxsize > )
status = ATCA_RX_FAIL;
else
status = ATCA_RX_NO_RESPONSE;
break;
} if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS )
break; memcpy( data, &packet.data[], len );
} while (); _atcab_exit();
return status;
}

看看函数中粗斜体,执行的顺序就是wake->send->delay->receive.

如果hal_delay函数不准,就会导致这个地方delay会不准,就要导致芯片已经休眠了,才去发送receive命令,当然收不到。

还有一点,如果传输的速率比较低,也会导致在send的时候花很多时间,即使delay是准时的,也会导致芯片已经休眠,才去发送receive。

因为不知道库里有多少个地方是这样处理的,所以还是尽量将函数时间弄准确,I2C的速率尽量高点。

3.关于是如何发现这些问题的,我用到了逻辑分析仪:

从下图可以看出,我send command之后,delay了0.7248s才去receive,这个时候芯片早已休眠。

就是通过下图看出ATECC508芯片没有响应的。

最后上一张完整通讯的截图:

OpenSSL攻略.pdf

STM32L071CBTX操作ECC508的更多相关文章

  1. 关于DOM的操作以及性能优化问题-重绘重排

     写在前面: 大家都知道DOM的操作很昂贵. 然后贵在什么地方呢? 一.访问DOM元素 二.修改DOM引起的重绘重排 一.访问DOM 像书上的比喻:把DOM和JavaScript(这里指ECMScri ...

  2. Sql Server系列:分区表操作

    1. 分区表简介 分区表在逻辑上是一个表,而物理上是多个表.从用户角度来看,分区表和普通表是一样的.使用分区表的主要目的是为改善大型表以及具有多个访问模式的表的可伸缩性和可管理性. 分区表是把数据按设 ...

  3. C# ini文件操作【源码下载】

    介绍C#如何对ini文件进行读写操作,C#可以通过调用[kernel32.dll]文件中的 WritePrivateProfileString()和GetPrivateProfileString()函 ...

  4. js学习笔记:操作iframe

    iframe可以说是比较老得话题了,而且网上也基本上在说少用iframe,其原因大致为:堵塞页面加载.安全问题.兼容性问题.搜索引擎抓取不到等等,不过相对于这些缺点,iframe的优点更牛,跨域请求. ...

  5. jquery和Js的区别和基础操作

    jqery的语法和js的语法一样,算是把js升级了一下,这两种语法可以一起使用,只不过是用jqery更加方便 一个页面想要使用jqery的话,先要引入一下jqery包,jqery包从网上下一个就可以, ...

  6. ASP.NET Aries 入门开发教程7:DataGrid的行操作(主键操作区)

    前言: 抓紧勤奋,再接再励,预计共10篇来结束这个系列. 上一篇介绍:ASP.NET Aries 入门开发教程6:列表数据表格的格式化处理及行内编辑 本篇介绍主键操作区相关内容. 1:什么时候有默认的 ...

  7. 如何在高并发环境下设计出无锁的数据库操作(Java版本)

    一个在线2k的游戏,每秒钟并发都吓死人.传统的hibernate直接插库基本上是不可行的.我就一步步推导出一个无锁的数据库操作. 1. 并发中如何无锁. 一个很简单的思路,把并发转化成为单线程.Jav ...

  8. 【翻译】MongoDB指南/CRUD操作(四)

    [原文地址]https://docs.mongodb.com/manual/ CRUD操作(四) 1 查询方案(Query Plans) MongoDB 查询优化程序处理查询并且针对给定可利用的索引选 ...

  9. 【翻译】MongoDB指南/CRUD操作(三)

    [原文地址]https://docs.mongodb.com/manual/ CRUD操作(三) 主要内容: 原子性和事务(Atomicity and Transactions),读隔离.一致性和新近 ...

随机推荐

  1. R语言最优化(多维)

    线性搜索的最速上升法 #### max.search <- function(f, x, y, tol=1e-9, a.max = 2^5){ if(sum(abs(y)) == 0) retu ...

  2. Linux 设备驱动之字符设备

    参考转载博客:http://blog.chinaunix.net/uid-26833883-id-4369060.html https://www.cnblogs.com/xiaojiang1025/ ...

  3. spark中map与mapPartitions区别

    在spark中,map与mapPartitions两个函数都是比较常用,这里使用代码来解释一下两者区别 import org.apache.spark.{SparkConf, SparkContext ...

  4. 重新复习~ 为了重新找工作 - > XMLHttpRequest2.0 Jsonp nodeType 节点 webpack基本搭建 闭包的一句话总结

    XMLHttpRequest2.0 1.可以设置超时 (xhr.timeout = 1000; ontimeout()函数) 2.支持FormData对象管理表单数据(new FormData 方法: ...

  5. 【SoftwareTesting】Homework3

    (a) (b) 数组越界问题 (c) n=0 (d) 点覆盖:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] 边覆盖:[(1,2),(2,3),(3,4),(4,5) ...

  6. 初读"Thinking in Java"读书笔记之第六章 --- 访问权限控制

    包:库单元 包内包含有一组类,他们在单一的名字空间下被组织在一起. 通过import ***.***.*可以将某个包下的所有类导入到当前文件中. 每个Java源文件最多只能有一个public类,且名称 ...

  7. Beta冲刺 6

    前言 队名:拖鞋旅游队 组长博客:https://www.cnblogs.com/Sulumer/p/10129063.html 作业博客:https://edu.cnblogs.com/campus ...

  8. MySQL5.7关于密码二三事

    MySQL5.7关于密码二三事 第一个:update user set password=password('root') where user='root' and host='localhost' ...

  9. 2017-9-3模拟赛T3 密码(key)

    题目 题解 这题用类似暴力+优化(划掉)的思想. 对于每个轨迹串,求出每一位向后的第一个0-9间某个数字的位置(如123112中3后面第1个2的位置为从左往右数第6个),复杂度O(Σn)=O(L). ...

  10. re模块基本用法和字符集

    import re # . 能够替代任意字符 r= re.findall("a..c","abbcsd") print(r) # ^ 找最前面的 r_1 = r ...