SPI_master


前言

用FPGA实现SPI主机


一、SPI 特性

1.1同步

发送数据时钟+发送数据

1.2速率

I2C协议v2.1规定了100K,400K和3.4M三种速率(bps)。

具体到产品中SPI的速率为系统时钟频率的1/2。

1.3全双工

两根数据线

二、数据接口

2.1主从机连接

在这里插入图片描述

2.2传输模式

MODECPLOCPHL
000
101
210
311

二、难点

2.1 难点1:SPI数据是在下降沿变化,上升沿保持

解决思路:对系统时钟产生二分频计数器,既可以指示spi_clk上升下降沿,又可以在spi_clk时钟下降沿改变数据,上升沿数据保持。

2.2 难点2:串并转换

思路:串转并移位寄存器往里填数,并转串移位移位寄存器往外溢数

always@(posedge i_clk)begin
    if(i_rst)
        ro_spi_mosi <= 'd0;
    else if(w_user_active)
        ro_spi_mosi <= i_user_data[cnt];//并转串
    else 
        ro_spi_mosi <= ro_spi_mosi;
end 


always@(posedge ro_spi_clk,posedge i_rst)begin
    if(i_rst)
        user_data <= 'd0;
    else
        user_data <= {user_read_data[6 : 0],i_spi_miso};//串转并
end

3 仿真

简单仿真验证一下逻辑,输出信号下降沿变化,对应从机就是上升沿读取数据,没啥问题,ok
在这里插入图片描述


备注

仅用于记录日常学习,侵权必究

#include "spi_master_server.h" // SPI 头文件 #include <SPI.h> #include "helper.h" #include <Adafruit_SPIDevice.h> // Adafruit SPIDevice 封装类对象 Adafruit_SPIDevice *spi_dev = nullptr; #define SPI_MASTER_ENABLE 1 // 自定义引脚定义(与原从机对应) #define MY_CS 12 #define MY_SCK 13 #define MY_MOSI 14 #define MY_MISO 11 // 超时时间 #define SPI_READ_TIMEROUT 999999 // us // 缓冲区大小:32 字节 static constexpr size_t SPI_BUFFER_SIZE = 16 * 2; static constexpr size_t QUEUE_SIZE = 1; // 保留兼容字段,实际主机不用队列 // 发送/接收缓冲区 static uint8_t spi_tx_buf[SPI_BUFFER_SIZE] = {1, 2, 3, 4, 5, 6, 7, 8}; // 测试数据 static uint8_t spi_rx_buf[SPI_BUFFER_SIZE] = {0}; // 命令发送缓冲区 static uint8_t spi_tx_cmd_buf[SPI_BUFFER_SIZE] = {0}; // 发送缓存配置 #define SPI_TX_CACHE_BUF_LEN 1024 #define SPI_TX_PAGE_BUF_LEN (SPI_BUFFER_SIZE - 3) // 协议头占3字节: 0xAB + len + seq // 用户命令定义 #define SPI_USER_CMD_NULL 0 #define SPI_USER_CMD_READ 1 #define SPI_USER_CMD_WRITE 2 static volatile int spi_current_cmd = 0; // 全局缓存及状态 static volatile uint8_t spi_tx_cache_buf[SPI_TX_CACHE_BUF_LEN] = {0}; static volatile int spi_tx_cache_buf_cnt = 0; static volatile int spi_current_cmd = 0; static volatile int spi_current_cmd_len = 0; // 标志位 static uint8_t spi_send_busy = 0; static uint8_t spi_send_mode = 1; // 默认使用 SPI 发送 int spi_master_data_cache_add(uint8_t *data, uint16_t len) { if (len > 1024) len = 1024; memcpy((void*)spi_tx_cache_buf, data, len); spi_tx_cache_buf_cnt = len; return 0; } void IRAM_ATTR my_pre_transfer_cb() { int page_len = SPI_BUFFER_SIZE - 3; int total_pages = (spi_tx_cache_buf_cnt + page_len - 1) / page_len; int current_page = spi_current_cmd_len; memset(spi_tx_buf, 0, SPI_BUFFER_SIZE); spi_tx_buf[0] = 0xAB; if (current_page >= total_pages) { spi_tx_buf[1] = 0; // no data spi_tx_buf[2] = current_page; return; } int offset = current_page * page_len; int data_len = min(page_len, spi_tx_cache_buf_cnt - offset); spi_tx_buf[1] = data_len; spi_tx_buf[2] = current_page; for (int i = 0; i < data_len; i++) { spi_tx_buf[3 + i] = spi_tx_cache_buf[offset + i]; } spi_current_cmd_len++; } static void spi_master_task(void *pvParameters) { while (1) { if (digitalRead(MY_CS) == LOW) { // 从机请求通信 memset(spi_rx_buf, 0, SPI_BUFFER_SIZE); // 使用 writeThenRead 模拟全双工传输 bool success = spi_dev->write_then_read( spi_tx_buf, SPI_BUFFER_SIZE, // 发送的数据和长度 spi_rx_buf, SPI_BUFFER_SIZE, // 接收缓冲区和长度 0 // 命令/地址字节个数(无) ); if (success) { printf_log_hex("RX from slave", spi_rx_buf, SPI_BUFFER_SIZE); printf_log_hex("TX to slave", spi_tx_buf, SPI_BUFFER_SIZE); if (spi_rx_buf[1] == 0xAA && spi_rx_buf[2] == 0x01) { spi_current_cmd = SPI_USER_CMD_READ; } } else { printf("SPI transfer failed!\n"); } } vTaskDelay(5 / portTICK_PERIOD_MS); } } void spi_master_client_init(void) { #if SPI_MASTER_ENABLE // Step 1: 配置硬件 SPI 总线(HSPISPIClass hspi(HSPI); // 创建 HSPI 实例 hspi.begin(MY_SCK, MY_MISO, MY_MOSI, MY_CS); // 设置引脚 // Step 2: 创建 Adafruit_SPIDevice 对象 spi_dev = new Adafruit_SPIDevice( MY_CS, // CS pin 1000000, // 频率 1MHz SPI_BITORDER_MSBFIRST, SPI_MODE3, // CPOL=1, CPHA=1 &hspi // 使用自定义 SPIClass ); if (!spi_dev->begin()) { printf("SPI Device init failed!\n"); return; } // 创建任务 xTaskCreate(spi_master_task, "spi_master_task", 8192, NULL, 2, NULL); #endif } 在主函数调用该代码
09-26
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

徕卡

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值