FreeRTOS SPI 时序以及模拟SPI时序

SPI(Serial Peripheral Interface),顾名思义就是串行外围设备接口。SPI,是一种高速的全双工同步的通信总线,并且在芯片的管脚上只占用四根线(MISO, MOSI, CLK, CS)可以不用CS片选引脚也是三线式,SPI有时候可以不用MISO, MOSI,中的一个,但CLK的引脚一定需要存在。SPI节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。

Motorola公司推出的三线同步接口,同步串行3线方式进行通信:一条时钟线SCK,一条数据输入线MOSI,一条数据输出线MISO(不存在片选引脚);用于 CPU与各种外围器件进行全双工、同步串行通讯

SPI存在四种工作模式分别由POL(极性)与PHA(相位)决定。
POL = 0(CLK时钟的空闲电平为低电平)
POL = 1(CLK时钟的空闲电平为高电平)
PHA = 0(CLK时钟下第一个跳变沿进行数据采集
PHA = 1(CLK时钟下第二个跳边沿进行数据采集
以下是SPI四种传输模式第一种与第三种使用广泛。
如下图所示:
SPI四种传输模式SPI内部结构
主机与从机共用同一个时钟,达到同步的目的。
SPI内部结构SPI编程实现

struct spi_config_data {
    unsigned int id;        /* SPI 控制器 ID */
    unsigned int cs_pin;    /* 指定作为 cs 脚的 GPIO */
    char *name;             /* name 仅作为一个标识 */
    unsigned int clk_rate;  /* 时钟频率(默认为 1*1000*1000) */

    enum spi_cs_valid_level cs_valid_level; /* 有效电平 */

    /* 数据传输的大小端模式选择,具体可选类型为 spi_data_endian 所定义的类型 */
    enum spi_data_endian tx_endian;
    enum spi_data_endian rx_endian;

    /* bits_per_word 代表数据的位宽.
        例如:bits_per_word = 32 时,SPI传输过程中的最小数据单位为32bit. */
    unsigned int bits_per_word;

    /**
     * 极性 spi_pol :
     * 当spi_pol=0,在时钟空闲即无数据传输时,clk电平为低电平
     * 当spi_pol=1,在时钟空闲即无数据传输时,clk电平为高电平
     * 相位 spi_pha :
     * 当spi_pha=0,表示在第一个跳变沿开始采集数据
     * 当spi_pha=1,表示在第二个跳变沿开始采集数据
     */
    unsigned int spi_pol;
    unsigned int spi_pha;

    unsigned int loop_mode; /* 循环模式,可用于测试 */
};

struct spi_device {
    struct spi_config_data config;
    struct list_head spi_drv_node;
};

/*获取时钟,初始化对应的IO口
*/
void soc_spi_init_driver(void);
/*初始化片选引脚,并将设备添加到链表中
*/
void soc_spi_register(struct spi_config_data *config);
/*传输msg
*/
void soc_spi_transfer(struct spi_device *spi, struct spi_message *msg, int count);
/*释放IO口,删除对应的节点
*/
void soc_spi_unregister(struct spi_device *spi);

其实spi传输数据,并不是只传输8,18,32位,这种特殊位的数据。优秀的应该做到2~32可调,并以 8, 16, 32位对齐。少于的都属于无效位。
以模拟gpio spi为例(以下是我个人以为比较有好的代码)
接口框架以上边相同(统一接口)

/*读采集通过传char数据,然后直接读取数据。
*/
unsigned int read_sample(const unsigned char *value, int bytes_per_sample);
/*写采集
*/
void write_sample(const unsigned char *rx_buf, int bytes_per_sample, unsigned int value);
/*读写采集
*/
unsigned int spi_write_read_sample(struct spi_gpio_config_data *config, int bits, unsigned int value);
/*spi传输协议每次之传输一个bit
*/
int spi_write_read_bit(struct spi_gpio_config_data *config, int bit);

static unsigned int spi_write_read_sample(struct spi_gpio_config_data *config, int bits, unsigned int value)
{
	int bit;
    int end = 0;
    int delta = -1;
    int start = bits;
    int i = start;
    unsigned int ret = 0;

    while (1) {
        bit = spi_write_read_bit(config, value & (1 << i));

        if (bit)
            ret |= (1 << i);
        i += delta;
		
        if (i == end)
            break;
    }

    return ret;
}

今天用错一个互斥锁,在注册spi设备时,用互斥锁进行保护设备节点添加到全局链表。不过多个spi所用的互斥锁并不是同一把锁,所以会导致第二把锁不能正常上锁。
解决方法
1、每个spi都定义一个自己的链表
2、用同一把锁进行上锁
3、使用临界区

#打卡第二天#有需要的可以联系博主QQ:1667869702

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS是一个非常受欢迎的实时操作系统(RTOS),用于嵌入式系统的开发。SPI(Serial Peripheral Interface)是一种常见的串行通信接口,用于在微控制器和外部设备之间传输数据。FreeRTOSSPI通信可以通过以下步骤进行。 首先,需要初始化SPI外设。这可以通过配置相关的寄存器和引脚来完成。具体的初始化过程取决于所使用的硬件平台和芯片。 一旦SPI外设初始化完成,就可以创建一个FreeRTOS任务。在该任务中,可以使用FreeRTOS提供的API来实现SPI通信。 要在FreeRTOS任务中使用SPI,可以使用类似于如下的代码段: ```c #include "FreeRTOS.h" #include "task.h" #include "spi.h" void spi_task(void *pvParameters) { // 定义SPI通信的变量和缓冲区 // ... while(1) { // 从外部设备读取数据 // ... // 向外部设备写入数据 // ... // 延时等待 // ... } } void main(void) { // 初始化SPI外设 // ... // 创建FreeRTOS任务 xTaskCreate(spi_task, "SPI Task", configMINIMAL_STACK_SIZE, NULL, 1, NULL); // 启动FreeRTOS调度器 vTaskStartScheduler(); while(1) { // 无限循环 } } ``` 在这个示例中,spi_task函数是一个FreeRTOS任务,用于执行SPI通信。在这个任务中,可以使用SPI外设的相关API来实现通信。此外,还可以使用FreeRTOS提供的延时函数来控制任务之间的时间间隔。 需要注意的是,以上代码只是一个简单的示例,并且具体的实现取决于所使用的硬件平台和芯片。在实际应用中,可能还需要考虑到诸如互斥信号量(Mutex Semaphore)来保护SPI资源的访问等更复杂的情况。 总结起来,FreeRTOSSPI通信的步骤包括初始化SPI外设和创建FreeRTOS任务,在任务中使用SPI的相关API进行通信。以上是一个简单的示例,具体的实现可能因硬件平台和芯片而异。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值