0x00 前言
本文对于芯片的裸片进行SPI的测试,使用硬件的定时器进行测试时钟的稳定,因为考虑到实际使用单独使用一个硬件定时器作为时钟太过奢侈,这里使用了简单的软件模拟定时器的实现。这里因为软件定时器的实现并不重要,只要满足当前的一定测试时钟的稳定性和精度满足测试要求即可。
0x10 测试环境
- demo单板
- 电脑一台不必多讲
- IAR 9+,主要是编译器支持会好些
- 某个不愿意透露具体型号的逻辑分析仪(没打广告)
其中,SPI模拟引脚的选择标准如下:
-
为标准的IO接口
- 可以用来直接测试,没有外部接入
0x20 测试代码与测试步骤
笔者尝试实现一个简单的Master模式下的简单收发SPI,发送一些指定字符实现当前的SPI模拟。
下为代码
void spi_soft_init()
{
//TIM -- 模拟当前的频率
user_timer_init();
spi_soft_obj.config.b.ENABLE = 1;
timer_id = timer_add(
0,
0,
0,
0,
0,
1,
0,
1,
0,
TIM_IRQHandler
);
}
#define CS_HIGH do{gpio_bit_set(GPIOA, GPIO_PIN_1) }while(0)
#define CS_LOW do{gpio_bit_reset(GPIOA, GPIO_PIN_1);}while(0)
#define CLK_SET(state) do{gpio_bit_write(GPIOA, GPIO_PIN_2, state);}while(0)
#define MOSI_SET(state) do{gpio_bit_write(GPIOA, GPIO_PIN_3, state);}while(0)
#define MISO_GET() (gpio_input_bit_get(GPIOA,GPIO_PIN_9))
#define spi_soft_close() timer_stop(timer_id)
#define spi_soft_open() timer_reset(timer_id)
enum
{
SOFT_SPI_DATA_IN = 0,
SOFT_SPI_DATA_OUT,
SOFT_SPI_DATA_MAX
};
typedef union
{
unsigned char d8;
struct
{
unsigned CPHA:1; //0-even-catch|1-odd-catch
unsigned CPOL:1; //0-low|1-high
unsigned DATASIZE:1; //0-8bit|1-16bit
unsigned FLASH_BIT:1; //0-MSB|1-LSB
unsigned MODE:1; //0-master|1-slave
unsigned DIR:2; //0-Full duplex|1-onlyRX|2-onlyTX|3-Only_listen
unsigned ENABLE :1; //0-off|1-on
}b;
}S_SPI_CONFIG;
typedef struct
{
unsigned CLK:1;
unsigned CS:1;
unsigned MOSI:1;
unsigned MISO:1;
unsigned NU :28;
}S_SPI_SOFT_PIN;
typedef struct
{
unsigned short data[SOFT_SPI_DATA_MAX];
S_SPI_CONFIG config;
unsigned char line_state;//0-pending|1-sending
unsigned char send_point;
}S_SPI_SOFT_OBJ;
static S_SPI_SOFT_OBJ spi_soft_obj = {0};
S_SPI_SOFT_PIN spi_pin = {0};
void TIM_IRQHandler()
{
{
if(spi_soft_obj.config.b.ENABLE == 1)
{
//normal-no send
if(spi_soft_obj.line_state == 0)
{
if(spi_soft_obj.config.b.CPOL)
{
spi_pin.CLK = 1;
}
else
{
spi_pin.CLK = 0;
}
//spi_pin.MOSI = 0;
if(spi_pin.CS == 1)
{
//MSB
if(spi_soft_obj.config.b.FLASH_BIT == 0)
{
spi_soft_obj.data[SOFT_SPI_DATA_IN] |= MISO_GET();
}
//LSB
else
{ //no debug
spi_soft_obj.data[SOFT_SPI_DATA_IN] |= MISO_GET()<<((8*(spi_soft_obj.config.b.DATASIZE+1)));
}
}
spi_pin.CS = 0;
update_bit =0;
clock_count = 0;
spi_bit_count = 0;
}
//send-once byte
else
{
if((clock_count == 0))
{
spi_soft_obj.data[SOFT_SPI_DATA_IN] = 0;
}
//0-CPHA=0
if((!spi_soft_obj.config.b.CPHA) && (clock_count == 0))
{
update_bit = 1;
spi_pin.CLK = 0;
}
else
{
spi_pin.CLK = !spi_pin.CLK;
if((clock_count % 2) == (spi_soft_obj.config.b.CPHA))
{
update_bit = 1;
}
else
update_bit = 0;
}
clock_count++;
//send_finish
if((8*(spi_soft_obj.config.b.DATASIZE+1)) <= spi_bit_count)
{
spi_soft_obj.line_state = 0;
//spi_pin.MOSI = 0;
spi_pin.CS = 1;
update_bit =0;
clock_count = 0;
spi_bit_count = 0;
}
if(update_bit)
{
spi_pin.MISO = MISO_GET();
//MSB
if(spi_soft_obj.config.b.FLASH_BIT == 0)
{
spi_pin.MOSI = spi_soft_obj.data[SOFT_SPI_DATA_OUT] >> ((8*(spi_soft_obj.config.b.DATASIZE+1)) - spi_bit_count - 1 ) & 0x01;
spi_soft_obj.data[SOFT_SPI_DATA_IN] |= MISO_GET()<<((8*(spi_soft_obj.config.b.DATASIZE+1))- spi_bit_count );
}
//LSB
else
{ //no debug
spi_pin.MOSI = spi_soft_obj.data[SOFT_SPI_DATA_OUT] >> (spi_bit_count) & 0x01;
spi_soft_obj.data[SOFT_SPI_DATA_IN] |= MISO_GET()<<(spi_bit_count);
}
spi_bit_count++;
}
}
CLK_SET(spi_pin.CLK);
MOSI_SET(spi_pin.MOSI);
}
else
{
CLK_SET(0);
MOSI_SET(0);
}
}
}
需要提出的一点,这里的代码某些引脚与笔者现在的实际引脚相对不同,主要是官方的单板与这边测试的一些原因影响。不影响代码的实现
直接使用逻辑分析仪进行测试当前的协议是否正常发送数据。
这里笔者选反了数据输出,但是因为也是随手写的,也就不怎么重要的一个事情了。
0x30 测试结果与总结
可以看到,在稳定发送数据的情况下,芯片可以实现12.5KHz的时钟,还是可以使用的,虽说肯定不如硬件的SPI速度快或者方便,但是还是很满足兼容性的。而且这个速度还是在比较不影响当前系统的执行效率下的实现。
|