STM32
直播中

小麦地

11年用户 1605经验值
私信 关注
[问答]

怎样通过STM32使用SPI写入命令字节来实现对32个寄存器的读写操作呢

SPI的特性有哪些?
怎样通过STM32使用SPI写入命令字节来实现对32个寄存器的读写操作呢?

回帖(2)

张瑜

2021-12-17 13:43:08
本设计在FPGA用32个寄存器构建了一个8bit*32的ROM,可通过STM32使用SPI写入命令字节来实现对32个寄存器的读写操作。
  命令字节的格式:
  bit 7:读写控制位,
        1:W
        0:R
  bit6-bit2:寄存器地址
  bit1-bit0:未使用
  stm32的代码基于正电原子的探索者开发板和工程,使用软件模拟SPI,FPGA使用Verilog编写。
  SPI的特性为:时钟空闲时为高电平,在时钟的下降沿将数据输出,在时钟的上升沿读取数据。
  主要代码:
  FPGA代码:

  1 SPI从机部分

// 32位二段式状态机spi模块
module spi_slave16bit(
        input wire clk,
        input rst_n,
        input wire CS,
        input wire SCK,
        input wire MOSI,
        output reg MISO,
        output reg [5:0]rom_addr,
        output reg busy,//spi给fpga其他模块,busy=1时,禁止FPGA读写
        input wire[15:0] data_to_out,
        output reg[15:0] data_had_receive,
  output rxd_over //rx 2byte will generate pulse
  );

reg [1:0] state;
parameter IDLE = 2'b00;
parameter TRANS = 2'b01;
parameter WAIT = 2'b10;

reg [1:0]CS_buf;
wire CS_falling_flag;
wire CS_rising_flag;
always@(posedge clk)
begin
        CS_buf[1] <= CS_buf[0];
        CS_buf[0] <= CS;
end
assign CS_falling_flag = CS_buf[1] &(~CS_buf[0]);
assign CS_rising_flag = (~CS_buf[1]) & CS_buf[0];

reg [1:0]SCK_buf;
wire SCK_falling_flag;
wire SCK_rising_flag;
always@(posedge clk)
begin  
     SCK_buf[1] <= SCK_buf[0];
          SCK_buf[0] <= SCK;
end

assign SCK_falling_flag = SCK_buf[1]&(~SCK_buf[0]);
assign SCK_rising_flag = (~SCK_buf[1])&SCK_buf[0];

reg [5:0]count;
// state machine
always@(posedge clk)
begin
  
        case(state)
                IDLE:begin
                                 if(CS_falling_flag==1) state <= TRANS;
                          end
                TRANS:begin
                                        if(count == 6'b010000) state <= WAIT; // 传完16个数
                                        else if (CS_rising_flag==1) state <= IDLE; // 意外结束
                                end
                WAIT:begin
                                 if (CS_rising_flag) state <= IDLE;
                          end
        endcase
end

// count
always@(posedge clk)
begin
        case(state)
                IDLE: count<=6'b0;
                TRANS:begin
                                        if(SCK_rising_flag == 1) count <= count + 6'b1;
                                end
        endcase
end

// MISO
always@(posedge clk)
begin
        if ((state == TRANS)&&(SCK_falling_flag == 1))
        begin
                case(count)
                        6'b000000: MISO <= data_to_out[15];
                        6'b000001: MISO <= data_to_out[14];
                        6'b000010: MISO <= data_to_out[13];
                        6'b000011: MISO <= data_to_out[12];
                        6'b000100: MISO <= data_to_out[11];
                        6'b000101: MISO <= data_to_out[10];
                        6'b000110: MISO <= data_to_out[9];
                        6'b000111: MISO <= data_to_out[8];
                        6'b001000: MISO <= data_to_out[7];
                        6'b001001: MISO <= data_to_out[6];
                        6'b001010: MISO <= data_to_out[5];
                        6'b001011: MISO <= data_to_out[4];
                        6'b001100: MISO <= data_to_out[3];
                        6'b001101: MISO <= data_to_out[2];
                        6'b001110: MISO <= data_to_out[1];
                        6'b001111: MISO <= data_to_out[0];
/*                         6'b010000: MISO <= data_to_out[15];
                        6'b010001: MISO <= data_to_out[14];
                        6'b010010: MISO <= data_to_out[13];
                        6'b010011: MISO <= data_to_out[12];
                        6'b010100: MISO <= data_to_out[11];
                        6'b010101: MISO <= data_to_out[10];
                        6'b010110: MISO <= data_to_out[9];
                        6'b010111: MISO <= data_to_out[8];
                        6'b011000: MISO <= data_to_out[7];
                        6'b011001: MISO <= data_to_out[6];
                        6'b011010: MISO <= data_to_out[5];
                        6'b011011: MISO <= data_to_out[4];
                        6'b011100: MISO <= data_to_out[3];
                        6'b011101: MISO <= data_to_out[2];
                        6'b011110: MISO <= data_to_out[1];
                        6'b011111: MISO <= data_to_out[0]; */
                endcase
        end
end

// MOSI
reg rxd_flag_r;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
   rxd_flag_r <= 0;
  else
begin
        if ((state == TRANS)&&(SCK_rising_flag == 1))
        begin
                case(count)
                        6'b000000: begin data_had_receive[15] <= MOSI;rxd_flag_r<=1'b0;end
                        6'b000001: data_had_receive[14] <= MOSI;
                        6'b000010: data_had_receive[13] <= MOSI;
                        6'b000011: data_had_receive[12] <= MOSI;
                        6'b000100: data_had_receive[11] <= MOSI;
                        6'b000101: begin
                  data_had_receive[10] <= MOSI; //set rom addr
                  rom_addr[5:0] <= {data_had_receive[15:11],MOSI};
                 end
                        6'b000110: data_had_receive[9] <= MOSI;
                        6'b000111: data_had_receive[8] <= MOSI;
                        6'b001000: data_had_receive[7] <= MOSI;
                        6'b001001: data_had_receive[6] <= MOSI;
                        6'b001010: data_had_receive[5] <= MOSI;
                        6'b001011: data_had_receive[4] <= MOSI;
                        6'b001100: data_had_receive[3] <= MOSI;
                        6'b001101: data_had_receive[2] <= MOSI;
                        6'b001110: data_had_receive[1] <= MOSI;
                        6'b001111: begin data_had_receive[0] <= MOSI; rxd_flag_r<=1'b1;end
/*                         6'b010000: data_had_receive[15] <= MOSI;
                        6'b010001: data_had_receive[14] <= MOSI;
                        6'b010010: data_had_receive[13] <= MOSI;
                        6'b010011: data_had_receive[12] <= MOSI;
                        6'b010100: data_had_receive[11] <= MOSI;
                        6'b010101: data_had_receive[10] <= MOSI;
                        6'b010110: data_had_receive[9] <= MOSI;
                        6'b010111: data_had_receive[8] <= MOSI;
                        6'b011000: data_had_receive[7] <= MOSI;
                        6'b011001: data_had_receive[6] <= MOSI;
                        6'b011010: data_had_receive[5] <= MOSI;
                        6'b011011: data_had_receive[4] <= MOSI;
                        6'b011100: data_had_receive[3] <= MOSI;
                        6'b011101: data_had_receive[2] <= MOSI;
                        6'b011110: data_had_receive[1] <= MOSI;
                        6'b011111: data_had_receive[0] <= MOSI; */
                endcase
        end
end
end

reg rxd_flag_r0,rxd_flag_r1;
always@(negedge rst_n or posedge clk)
begin
    if(!rst_n)
        begin
            rxd_flag_r0 <= 1'b0;
            rxd_flag_r1 <= 1'b0;
        end
    else
        begin
            rxd_flag_r0 <= rxd_flag_r;
            rxd_flag_r1 <= rxd_flag_r0;
        end
end
assign rxd_over = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;
// busy
always@(posedge clk)
begin
        case(state)
                IDLE: busy <= 0;
                TRANS: busy <= 1;
                WAIT: busy <= 0;
        endcase
end

endmodule
2 寄存器构成ROM模块

module spi_rom
              (
               rst,
               rxd_flag,
               reg_addr,
               reg_out,
               rxd_in_spi
              );

input rst,rxd_flag;
input [5:0] reg_addr;
input [15:0] rxd_in_spi;
output reg [7:0] reg_out;              
reg [7:0] REG_ROM[31:0];

always@(negedge rst or posedge rxd_flag)
begin
  if(!rst)
  begin
    REG_ROM[0] <= 8'd0;
    REG_ROM[1] <= 8'd1;
    REG_ROM[2] <= 8'd2;
    REG_ROM[3] <= 8'd3;
    REG_ROM[4] <= 8'd4;
    REG_ROM[5] <= 8'd5;
    REG_ROM[6] <= 8'd6;
    REG_ROM[7] <= 8'd7;
    REG_ROM[8] <= 8'd8;
    REG_ROM[9] <= 8'd9;
    REG_ROM[10] <= 8'd10;
    REG_ROM[11] <= 8'd11;   
    REG_ROM[12] <= 8'd12;
    REG_ROM[13] <= 8'd13;
    REG_ROM[14] <= 8'd14;
    REG_ROM[15] <= 8'd15;
    REG_ROM[16] <= 8'd16;
    REG_ROM[17] <= 8'd17;
    REG_ROM[18] <= 8'd18;
    REG_ROM[19] <= 8'd19;
    REG_ROM[20] <= 8'd20;
    REG_ROM[21] <= 8'd21;
    REG_ROM[22] <= 8'd22;  
    REG_ROM[23] <= 8'd23;
    REG_ROM[24] <= 8'd24;   
    REG_ROM[25] <= 8'd25;
    REG_ROM[26] <= 8'd26;
    REG_ROM[27] <= 8'd27;
    REG_ROM[28] <= 8'd28;
    REG_ROM[29] <= 8'd29;
    REG_ROM[30] <= 8'd30;
    REG_ROM[31] <= 8'd31;   
  end
  else
   begin
      if(rxd_in_spi[15]==1'b1)
       REG_ROM[rxd_in_spi[14:10]] = rxd_in_spi[7:0];
   end
end
always@(reg_addr)
begin
   if(reg_addr[5]==0)
    reg_out=REG_ROM[reg_addr[4:0]];
   else reg_out=8'd0; //if write and next byte will tx 8'b0
   
end

/* always@(posedge rxd_flag)
begin
  if(rxd_in_spi[15]==1'b1)
   REG_ROM[rxd_in_spi[14:10]] = rxd_in_spi[7:0];
end          */   
endmodule              
3 顶层模块

module TEST_MODULE
                (
                clk,
                rst,
                cs,
                sck,
                MOSI,
                MISO,
                led_pin,
                rxd_over
                 );
                 
input clk,rst,cs,sck,MOSI;
output MISO,led_pin,rxd_over;
wire rxd_flag;
wire [5:0] rom_addr;  
wire [7:0] reg_out;  
wire [15:0]rxd_in_spi;
wire spi_busy;
wire rxd_over;
wire [7:0] dat_to_out;

//always@(posedge clk)
//begin
// if(!spi_busy)
//  dat_to_out[15:8] <= 8'd255;
//end

LED_module LED_module_inst
          (
          .clk(clk),
          .rst(rst),
          .led_pin(led_pin)
          );  

spi_slave16bit(
         .clk(clk),
         .rst_n(rst),
         .CS(cs),
         .SCK(sck),
         .MOSI(MOSI),
         .MISO(MISO),
         .rom_addr(rom_addr),
         .busy(spi_busy),//spi给fpga其他模块,busy=1时,禁止FPGA读写
         .data_to_out({8'hff,dat_to_out}),//first byte TX 0hff
         .data_had_receive(rxd_in_spi),
   .rxd_over(rxd_over)
  );
         
spi_rom spi_rom_inst
              (
               .rst(rst),
               .rxd_flag(rxd_over),
               .reg_addr(rom_addr),
               .reg_out(dat_to_out),
               .rxd_in_spi(rxd_in_spi)
              );
  
endmodule
举报

丁滢

2021-12-17 13:43:12
SMT32部分

  1 头文件及部分定义

#define SPI_CS  PGout(7)                  
#define SPI_MISO  PBin(4)        
#define SPI_MOSI  PBout(5)        
#define SPI_CLK  PBout(3)

void soft_spi_ioinit(void);
u8 get_cmd(u8 wr,u8 addr);
u8 spi_read2byte(u8 reg_addr);
u8 spi_write2byte(u8 reg_addr,u8 dat);       
2 函数声明部分

void soft_spi_ioinit()
{

        GPIO_InitTypeDef  GPIO_InitStructure;
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//ʹÄÜGPIOB,GʱÖÓ
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;              //CS
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//ÆÕͨÊä³öģʽ
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//ÍÆÍìÊä³ö
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//ÉÏÀ­
  GPIO_Init(GPIOG, &GPIO_InitStructure);//³õʼ»¯PG6,7
        SPI_CS=1;                        //SPIƬѡȡÏû       
       
       
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//ʹÄÜGPIOAʱÖÓ


  //GPIOFB3,5³õʼ»¯ÉèÖÃ
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_5;//PB3~5¸´Óù¦ÄÜÊä³ö       
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//¸´Óù¦ÄÜ
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//ÍÆÍìÊä³ö
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//ÉÏÀ­
  GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ»¯
        SPI_CLK = 1;
       
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;//PB3~5¸´Óù¦ÄÜÊä³ö       
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//ÆÕͨÊäÈëģʽ
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;//100M
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//ÉÏÀ­
  GPIO_Init(GPIOB, &GPIO_InitStructure);//³õʼ»¯
               
}

u8 get_cmd(u8 wr,u8 addr)//wr=1:w  wr=0:r addr:0-31
{
   u8 reg=0;
         //if(wr) reg = 128;
         reg = wr;
         reg = reg<<5;
         reg =  reg+addr;
         reg =reg<<2;
         return reg;
};

u8 spi_read2byte(u8 reg_addr) //reg_addr:0-31
{
  u32 tmp=0;
        u8 i=0;
        u8 addr;
        SPI_CS = 1;
        SPI_CLK = 1;
        SPI_CS = 0;
       
        addr = get_cmd(0,reg_addr);
       
        delay_us(1);
  for(i=0;i<8;i++)
        {
         SPI_CLK = 1;
                if(addr&0x80)SPI_MOSI = 1;
           else SPI_MOSI = 0;
                addr = addr<<1;
         delay_us(1);
         SPI_CLK = 0;
         delay_us(1);
         SPI_CLK = 1;
         tmp =tmp<<1;
         tmp = tmp+SPI_MISO;
        }
        delay_us(2);
          for(i=0;i<8;i++)
        {
         SPI_CLK = 1;
    SPI_MOSI = 1;
         delay_us(1);
         SPI_CLK = 0;
         delay_us(1);
         SPI_CLK = 1;
         tmp =tmp<<1;
         tmp = tmp+SPI_MISO;
        }
        SPI_CLK = 1;
        SPI_CS = 1;
       
        return tmp&0x00ff;
       
}

u8 spi_write2byte(u8 reg_addr,u8 dat)
{
  u32 tmp=0;
        int i=0;
        u8 addr;
        u8 dat_buff = dat;
        SPI_CS = 1;
        SPI_CLK = 1;
        SPI_CS = 0;
        delay_us(1);
       
        addr = get_cmd(1,reg_addr);
       
  for(i=0;i<8;i++)
        {
         SPI_CLK = 1;
                if(addr&0x80)SPI_MOSI = 1;
           else SPI_MOSI = 0;
                addr = addr<<1;
         delay_us(1);
         SPI_CLK = 0;
         delay_us(1);
         SPI_CLK = 1;
         tmp =tmp<<1;
         tmp = tmp+SPI_MISO;
        }
       
        delay_us(2);
       
        for(i=0;i<8;i++)
        {
         SPI_CLK = 1;
                 if(dat_buff&0x80)SPI_MOSI = 1;
       else SPI_MOSI = 0;
                dat_buff = dat_buff<<1;
         delay_us(1);
         SPI_CLK = 0;
         delay_us(1);
         SPI_CLK = 1;
         tmp =tmp<<1;
         tmp = tmp+SPI_MISO;
        }
        SPI_CLK = 1;
        SPI_CS = 1;
       
        return tmp&0x00ff;
}
3 主函数

int main(void)
{
        u8 key,mode;
        u8 t=0;
        u32 error_num=0;
        u32 read_num=0;
  u32 rec=0;       
        u8 tmp_buf[33];       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//ÉèÖÃϵͳÖжÏÓÅÏȼ¶·Ö×é2
        delay_init(168);  //³õʼ»¯ÑÓʱº¯Êý
        uart_init(115200);        //³õʼ»¯´®¿Ú²¨ÌØÂÊΪ115200
        LED_Init();                                        //³õʼ»¯LED
//         LCD_Init();                                        //LCD³õʼ»¯  
//         KEY_Init();                                        //°´¼ü³õʼ»¯
//         NRF24L01_Init();                    //³õʼ»¯NRF24L01
   soft_spi_ioinit();
  //NRF24L01_Read_Reg(reg);
        while(1)
        {       
               
    for(t=0;t<32;t++)
                {
                //key = get_reg(0,t);
                key = rand()%100;
                spi_write2byte(t,key);
                       
                rec = spi_read2byte(t);
                  
                if(rec!=key)
                {
                 error_num++;
                 printf("error_num = %drn",error_num);
                }
                   read_num++;
                  if(read_num%100==0)
                        {
                         
       printf("error_num = %drn",error_num);                               
                        }
                        printf("send = %d   rec_num = %d   read_num = %drn",key,rec,read_num);
                  rec = 0;
                //if(key==5)
                        //else  printf("key = %d ERRORrn",key);       
                delay_ms(100);       
                }
         
   
                t++;               

       
        }     
               
}
运行结果

  读写上万次无错误
  
  

  

   
举报

更多回帖

发帖
×
20
完善资料,
赚取积分