一. SPI 实验
SPI实验:学习如何使用 I.MX6U 的 SPI 接口来驱动 ICM-20608,读取 ICM-20608 的六轴数据。
ICM20608 传感器包括陀螺仪与加速度计,还有温度值。本实验就是读取 陀螺仪的角速度,加速度计的加速值,以及芯片温度的值。
本文学习一下,开启 IMX6ULL芯片的硬件浮点支持操作(因为SPI实验读取的数据有浮点型数据)。
二. IMX6ULL开启硬件浮点
我们在使用浮点计算的时候程序卡死了。串口卡死的原因有两点,如下所示:
(1) IMX6ULL芯片没有开启硬件浮点运算。
(2) 在编译的时候没有使用浮点编译选项。
下面具体介绍 Cortex-A系列芯片硬件浮点的开启操作。
1. 开启硬件浮点运算
IMX6ULL芯片属于 Cortex-A7系列芯片,这里需要参考两个文档,在 "/参考资料" 目录下。分别为
" Cortex-A7 Technical ReferenceManua.pdf " 文档 与
"ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf "文档 。
IMX6ULL芯片支持硬件浮点功能,其中涉及两个寄存器的配置:CPACR寄存器与 FPEXC寄存器。
CPACR寄存器:(" Cortex-A7 Technical ReferenceManua.pdf " 文档中)
bit[31]: 与 VFP指令有关,VFP即 Vector Float Point,向量浮点体系结构。该位写 0。
bit[30]: 说明 "All instructions accessing D0-D31 execute normally. ",而寄存器 D0-D31是双精度寄存器。该位写 0。
bit[23:22]:与 cp11协处理器有关。这两位写 11。
bit[21:20]: 与 cp10协处理器有关。这两位写 11。
(经过百度可以知道,ARMv7-A架构的芯片,CP10、CP11 两个协处理器一起,提供了浮点运算和向量操作,以及高级的 SIMD 指令扩展。)
FPEXC寄存器:("ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf " 文档)
bit[30]: "Enable bit. A global enable for the Advanced SIMD and Floating-point Extensions",可以看出涉及 浮点操作的使能。该位置 1。
main.c文件添加 硬件浮点函数,实现如下:
//使能I.MX6U的硬件浮点支持,即NEON和FPU
void imx6ul_hardfpu_enable(void)
{
uint32_t cpacr;
uint32_t fpexc;
/*使能NEON与FPU */
cpacr = __get_CPACR();
cpacr = (cpacr & ~(CPACR_ASEDIS_Msk | CPACR_D32DIS_Msk))
| (3UL << CPACR_cp10_Pos) | (3UL << CPACR_cp11_Pos);
__set_CPACR(cpacr);
fpexc = __get_FPEXC();
fpexc |= 0x40000000UL;
__set_FPEXC(fpexc);
}
主函数中添加 函数的调用,如下:
int main(void)
{
unsigned char state = OFF;
char icm_buffer[20] = {0};
imx6ul_hardfpu_enable(); //开启硬件浮点支持与NEON
int_init(); /* 初始化中断(一定要最先调用!) */
imx6u_clkinit(); /* 初始化系统时钟 */
delay_init(); /* 初始化延时 */
clk_enable(); /* 使能所有的时钟 */
led_init(); /* 初始化led */
beep_init(); /* 初始化beep */
uart_init(); /* 初始化串口,波特率115200 */
rtc_init(); /* RTC时钟初始化 */
while(icm20608_spi_init()) /*SPI从设备ICM20608初始化 */
{
printf("---SPI--not check icm20608!!!\r\n");
}
while(1)
{
icm20608_get_data();
decimal_data_handle(icm20608_dev.accel_x_act, icm_buffer);
printf("acce-x: %s\r\n", icm_buffer);
decimal_data_handle(icm20608_dev.accel_y_act, icm_buffer);
printf("acce-y: %s\r\n", icm_buffer);
decimal_data_handle(icm20608_dev.accel_z_act, icm_buffer);
printf("acce-z: %s\r\n", icm_buffer);
decimal_data_handle(icm20608_dev.gyro_x_act, icm_buffer);
printf("gyro-x: %s\r\n", icm_buffer);
decimal_data_handle(icm20608_dev.gyro_y_act, icm_buffer);
printf("gyro-y: %s\r\n", icm_buffer);
decimal_data_handle(icm20608_dev.gyro_z_act, icm_buffer);
printf("gyro-z: %s\r\n", icm_buffer);
decimal_data_handle(icm20608_dev.temp_act, icm_buffer);
printf("temperature: %s\r\n\n", icm_buffer);
state = !state;
led_switch(LED0, state);
delayms(500);
}
return 0;
}
2. 添加浮点编译选项
Makefile 文件添加 硬件浮点支持。添加项如下:
-march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard
-march=:指定目标架构的型号
-mfpu=:来指定浮点协处理的类型
-mfloat-abi=: 生成的代码采用硬浮点(FPU)调用接口。
Makefile文件在编译 .c 文件时需要添加。如下所示:
$(COBJS) : obj/%.o : %.c
$(CC) -Wall -march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard -Wa,-mimplicit-it=thumb -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $<
3. 运行程序
做完以上硬件浮点工作后,即可编译并运行程序。
串口打印的参数值,如下: