社区导航

 
快捷导航
  • 首页
  • 论坛
  • 查看新帖
  • 最新回复
  • 精华区
  • 社区活动
  • 联系管理员
  • 消灭零回复
  • E金币兑换
搜索
查看: 2345|回复: 0

STM32通过FSMC读取SDRAM

[复制链接]

82

TA的帖子

0

TA的资源

纯净的硅(初级)

Rank: 4

发表于 2012-12-12 11:39:34 | 显示全部楼层 |阅读模式
STM32通过FSMC读取SDRAM
    之前在icore板(STM32F103VC8 + EP4CE6E22C8)上已经实现STM32通过FSMC访问FPGA了,然后可以考虑STM32通过FSMC访问SDRAM了(SDRAM是挂在FPGA上的)。STM32通过FSMC不能直接操作SDRAM,但是在FPGA的协助下是可以实现的:
实现的思路:
1)用FPGA写个简单的SDRAM控制器(单个word读写,未采用突发读写)
2)结合之前做过的FSMC访问FPGA(FPGA相当于STM32的外部SRAM),即在FPGA内定义几个STM32可以读写的
     寄存器,比如:
#define ARM_FPGA_REG0 *((volatile unsigned short *)((u32)0x60000000))
#define ARM_FPGA_REG1 *((volatile unsigned short*)( (u32)0x60020000))
#define ARM_FPGA_REG2 *((volatile unsigned short*)( (u32)0x60040000))
#define ARM_FPGA_REG3 *((volatile unsigned short*)( (u32)0x60060000))
#define ARM_FPGA_REG4 *((volatile unsigned short*)( (u32)0x60080000))
#define ARM_FPGA_REG5 *((volatile unsigned short *)((u32)0x600a0000))
#define ARM_FPGA_REG6 *((volatile unsigned short *)((u32)0x600c0000))
#define ARM_FPGA_REG7 *((volatile unsigned short *)((u32)0x600e0000)
       在ARM_FPGA_REG0中写入的值是写SDRAM的地址(16bit),
       在ARM_FPGA_REG7中写入的值是写SDRAM的数据(16bit),
       在ARM_FPGA_REG0中写入的值是读SDRAM的地址(16bit),
       在ARM_FPGA_REG7中读出的值是读SDRAM的数据(16bit),

STM32中读写SDRAM的驱动如下:
/*往SDRAM的地址addr写入数据16bit  data*/
static void write_sdram(u16 addr, u16 data)
{
 ARM_FPGA_REG0 = addr;
 ARM_FPGA_REG7 = data;
}
/*读出SDRAM的地址addr中数据*/ 
static u16 read_sdram(u16 addr)
{
 ARM_FPGA_REG1 = addr;
 delay_cnt(0); //短延时,因为写入读地址后,FPGA开始读SDRAM,但是要等7-8个clk数据才读出来,
                              //故需要短延时实际函数调用有开销,实际发现  delay_cnt(0); 可以,但是省略延时是 不行的
 return(ARM_FPGA_REG7);
}   
static void delay_cnt(u8 count) //短延时
{
    while(count--);
}  
 

FPGA部分程序:
主模块:
module  STM32_FPGA(                                                                 
            input  main_clk,                                                 
            output arm_clk,                                                  
            output led,                                                      
            input [2:0] addr,                                                
            inout [15:0] data,                                               
            input FPGA_CS0,//FPGA片选                                        
            input RD,                                                        
            input WR,                                                        
                                                        
                                   ///SDRAM                                                                     
                                   inout  [15:0] sdram_data,                                                    
                                   output [11:0] sdram_addr,//row A0-A11,column A0-A7                           
                                   output [1:0]  sdram_bank,                                                    
                                   output [1:0]  sdram_dqm,                                                     
                                   output sdram_cs,                                                             
                                   output sdram_we,                                                             
                                   output sdram_ras,                                                            
                                   output sdram_cas,                                                            
                                   output sdram_sclk,                                                           
                                   output sdram_scke                         
                                );                                                                 



wire clk;

pll_50M               pll_50M_inst (
.inclk0 ( main_clk ),//25M
.c0 ( clk ),             //100M
.c1 ( arm_clk )      //8M    
 );


reg [24:0] cnt = 0;
always @(posedge clk)
    cnt <= cnt + 1'b1;  

assign led = cnt[24];  //闪灯,无关紧要



reg [15:0] addr_in;  
reg [15:0] ARM_FPGA_REG2;  
reg [15:0] ARM_FPGA_REG3;  
reg [15:0] ARM_FPGA_REG4;
reg [15:0] ARM_FPGA_REG5;  
reg [15:0] ARM_FPGA_REG6;
reg [15:0] data_in = 0; //写入数据  
wire [15:0] read_data; //读出数据  
 

wire rd_en = ~FPGA_CS0 && ~RD;

reg [15:0] data_reg;  
always @(posedge clk)                              
begin                                                
   if(rd_en)                                 
     begin                                           
        case(addr[2:0])                              
         3'd0   :  data_reg <= 16'd0;  //wtite only! //读为0       
         3'd1   :  data_reg <= 16'd0;   //读为0      
         3'd2   :  data_reg <= ARM_FPGA_REG2;        
         3'd3   :  data_reg <= ARM_FPGA_REG3;        
         3'd4   :  data_reg <= ARM_FPGA_REG4;        
         3'd5   :  data_reg <= ARM_FPGA_REG5;        
         3'd6   :  data_reg <= ARM_FPGA_REG6;        
         3'd7   :  data_reg <= read_data;        
         default:  ;                                 
        endcase                                 
     end                                                                                               
end                                            

/* WR上升沿sampling point */  
 
reg WR_tmp1;
reg WR_tmp2;
always @(posedge clk)
begin
     WR_tmp1 <= WR;
     WR_tmp2 <= WR_tmp1;
end  
 
wire WR_RISING = ~WR_tmp2 && WR_tmp1;//与clk同步  


reg word_wr_en = 0;
reg word_rd_en = 0;      
always @(posedge clk)                                
begin                                       
  if(WR_RISING)                             
     begin                                    
        case(addr[2:0])                       
         3'd0   :  begin addr_in <= data;  end   //写地址
         3'd1   :  begin addr_in <= data; word_rd_en <= 1; end   //读地址    
         3'd2   :  ARM_FPGA_REG2 <= data;     
         3'd3   :  ARM_FPGA_REG3 <= data;     
         3'd4   :  ARM_FPGA_REG4 <= data;     
         3'd5   :  ARM_FPGA_REG5 <= data;     
         3'd6   :  ARM_FPGA_REG6 <= data;     
         3'd7   :  begin data_in <= data; word_wr_en <= 1; end  //写数据  
         default:  ;                          
        endcase                          
     end
   else
  begin
       word_wr_en <= 0;
       word_rd_en <= 0; 
  end
end                                         

assign data =  rd_en ? data_reg : 16'hzzzz;

//////////////////////

sdram_opera    sd_opera_inst(                                                                             
                             .clk(clk),                                                                   
                             .word_rd_en(word_rd_en),                                                            
                             .word_wr_en(word_wr_en),                                                            
                                                                                                              
                             .addr_in({6'd0,addr_in}),//22位地址线          
                             .data_in(data_in),  //写入的数据                                                      
                                          
                             .sdram_addr(sdram_addr),//row A0-A11,column A0-A7                           
                             .sdram_data(sdram_data),                                                    
                             .sdram_bank(sdram_bank),                                                    
                             .sdram_dqm(sdram_dqm),                                                     
                                                                                                          
                             .read_data(read_data),                                                                                                
                                                                                                          
                             .sdram_cs(sdram_cs),                                                             
                             .sdram_we(sdram_we),                                                             
                             .sdram_ras(sdram_ras),                                                            
                             .sdram_cas(sdram_cas),                                                                                                                     
                             .sdram_scke(sdram_scke)                                                            
                             ); 


assign sdram_sclk = ~clk;
endmodule 



子模块:
/************************************************************************
 100M clk  
************************************************************************/
module sdram_opera(
                   input clk,  
                   input word_rd_en,
                   input word_wr_en,
 
   input [21:0] addr_in,//??????bank?row?column???2?12?8
                   input [15:0] data_in,  
                   //////////////////////////////////////////////////
                   output [11:0] sdram_addr,//row A0-A11,column A0-A7
                   inout  [15:0] sdram_data,
                   output [1:0]  sdram_bank,
                   output [1:0]  sdram_dqm,
                   
                   output reg [15:0] read_data,
                         
                   output sdram_cs,
                   output sdram_we,
                   output sdram_ras,
                   output sdram_cas,

                   output sdram_scke
                   );  
   

reg sdr_init_cs;     
reg sdr_init_we;     
reg sdr_init_ras;    
reg sdr_init_cas;    
reg sdr_init_scke;   
reg [11:0] sdr_init_addr;
reg [1:0]  sdr_init_bank;
reg [1:0]  sdr_init_dqm;


/*********************************************
????????????27?power up sequence
*********************************************/    
reg [3:0] init_state = 0;    
reg [15:0] power_up_cnt = 0;//??320us??????200us
reg [3:0] num = 0;   
reg init_done = 0;
always @(posedge clk)
begin
   case(init_state)
     0 :  begin
             init_done     <= 0;
             sdr_init_scke <= 1;
             sdr_init_cs   <= 1;
             sdr_init_we   <= 1;
             sdr_init_ras  <= 1;
             sdr_init_cas  <= 1;
             sdr_init_bank <= 2'b11;
             sdr_init_dqm  <= 2'b11;// L(U)DQM??
             init_state    <= 1;
          end
     1 :  begin                      //??????200us????320us 
             power_up_cnt <= power_up_cnt + 1;
             if(power_up_cnt[15])    //2^15 * 10ns = 320us
                begin
                    init_state <= 2; 
                end    
          end              
     2 :  begin                      //??bank??? ,????30ns                        
             num <= num + 1;
             if(num == 0)
               begin
                  sdr_init_cs  <= 0;          
                  sdr_init_ras <= 0; 
                  sdr_init_cas <= 1; 
                  sdr_init_we  <= 0;    
                  sdr_init_addr[10] <= 1; //`A10 <= 1;//?????A10??????bank  
               end
             else if(num == 1)
               begin                     
                  sdr_init_cs  <= 1;          
                  sdr_init_ras <= 1;          
                  sdr_init_cas <= 1;          
                  sdr_init_we  <= 1;                   
               end
             else if(num == 2)   
               begin                          
                   num <= 0;
                   init_state <= 3;     
               end                                    
          end 
     3 :  begin                      //???? Auto Refresh,????80ns                                                                                          
             num <= num + 1;                                                            
             if(num == 0)                                                               
               begin                                                                    
                  sdr_init_cs  <= 0;                                                         
                  sdr_init_ras <= 0;                                                         
                  sdr_init_cas <= 0;                                                         
                  sdr_init_we  <= 1;                                                                            
               end                                                                      
             else if(num == 1)                                                          
               begin                                                                    
                  sdr_init_cs  <= 1;                                                         
                  sdr_init_ras <= 1;                                                         
                  sdr_init_cas <= 1;                                                         
                  sdr_init_we  <= 1;                                                                                                                
               end                                                                      
             else if(num == 7)                                                          
               begin                                                                    
                   num <= 0;                                                            
                   init_state <= 4;                                                     
               end                                                                      
          end
     4 :  begin                      //?????? Auto Refresh,????80ns                                                                                                          
             num <= num + 1;                                                                  
             if(num == 0)                                                                     
               begin                                                                          
                  sdr_init_cs  <= 0;                                                               
                  sdr_init_ras <= 0;                                                               
                  sdr_init_cas <= 0;                                                               
                  sdr_init_we  <= 1;                                                               
               end                                                                            
             else if(num == 1)                                                                
               begin                                                                          
                  sdr_init_cs  <= 1;                                                               
                  sdr_init_ras <= 1;                                                               
                  sdr_init_cas <= 1;                                                               
                  sdr_init_we  <= 1;                                                               
               end                                                                            
             else if(num == 7)                                                                
               begin                                                                          
                   num <= 0;                                                                  
                   init_state <= 5;                                                           
               end                                                                            
          end
     5 :  begin                      //???????                                                                                                               
             num <= num + 1;                                                                  
             if(num == 0)                                                                     
               begin                                                                          
                  sdr_init_cs  <= 0;                                                               
                  sdr_init_ras <= 0;                                                               
                  sdr_init_cas <= 0;                                                               
                  sdr_init_we  <= 0;  
                  sdr_init_bank <= 2'b00;  
      sdr_init_addr <= 12'b00_1_00_010_0_000;//single bit,CL = 2
                  //sdr_init_addr <= 12'b00_0_00_010_0_111;//burst                                                          
               end                                                                            
             else if(num == 1)                                                                
               begin                                                                          
                  sdr_init_cs  <= 1;                                                               
                  sdr_init_ras <= 1;                                                               
                  sdr_init_cas <= 1;                                                               
                  sdr_init_we  <= 1;   
                  num <= 0;           
                  init_done <= 1;
                  init_state <= 6;                                                                
               end                                                                                                                       
          end  
     6 :  begin                   //?????                                                                                     
             init_done  <= 0;
             init_state <= 6;  
          end 
     default: init_state <= 0;  
   endcase
end


//WORD?????                                                               
reg word_wr_tmp1,word_wr_tmp2;                                                 
always @(posedge clk)                                                          
begin                                                                          
   word_wr_tmp1 <= word_wr_en;      //synchronised to clk                      
   word_wr_tmp2 <= word_wr_tmp1;                                               
end                                                                            
wire word_wr_pulse = (~word_wr_tmp2) & word_wr_tmp1; //1?clk??             

//WORD?????                                                                  
reg word_rd_tmp1,word_rd_tmp2;                                                    
always @(posedge clk)                                                             
begin                                                                             
   word_rd_tmp1 <= word_rd_en;      //synchronised to clk                         
   word_rd_tmp2 <= word_rd_tmp1;                                                  
end                                                                               
wire word_rd_pulse = (~word_rd_tmp2) & word_rd_tmp1; //1?clk??   
           
 
//??63ms??????  
parameter REFRESH_CYCLE  = 23'd6300000;
reg [22:0] refresh_cnt = 0; 
reg refresh_pulse;
always @(posedge clk)  
begin  
   if(refresh_cnt == REFRESH_CYCLE)
     begin
        refresh_cnt <= 0;
        refresh_pulse <= 1;        //????????
     end   
   else
     begin                   
        refresh_cnt <= refresh_cnt + 1;
        refresh_pulse <= 0;                              
     end
end
                                   
/***********************************
????????
************************************/
reg sdr_cs;               
reg sdr_we;               
reg sdr_ras;              
reg sdr_cas;                         
reg sdr_scke;             
reg [11:0] sdr_addr;      
reg [15:0] sdr_data;      
reg [1:0]  sdr_bank;      
reg [1:0]  sdr_dqm;       
/*********************************************              
???????? 
????63ms?????????64ms????            
*********************************************/ 
parameter POWER_UP         = 4'd0;
parameter IDLE             = 4'd1;
parameter AUTO_REFRESH     = 4'd2;
parameter WORD_READ        = 4'd3;
parameter WORD_WRITE       = 4'd4; 




`define   A10          sdr_addr[10]
`define   ROW_ADDR     sdr_addr[11:0]
`define   COL_ADDR     sdr_addr[7:0] 
             
reg [3:0] state = 0;      
reg [3:0] num_1 = 0; 
reg [8:0] num_2 = 0; 
reg refresh_enable;
reg word_wr_enable;
reg word_rd_enable;

always @(posedge clk)       
begin                       
   case(state)         
     POWER_UP :     begin             
                      // burst_wr_valid <= 0;
  num_1    <= 0;
                       num_2    <= 0;
                       sdr_cs   <= sdr_init_cs; 
                       sdr_we   <= sdr_init_we; 
                       sdr_ras  <= sdr_init_ras;
                       sdr_cas  <= sdr_init_cas;
                       sdr_scke <= sdr_init_scke; 
                       sdr_addr <= sdr_init_addr;
                       sdr_bank <= sdr_init_bank;
                       sdr_dqm  <= sdr_init_dqm;                                                            
                       if(init_done)
                         state <= IDLE;  
                    end      
     IDLE     :     begin
                       if(refresh_pulse)          //?????????????
                         begin
                            refresh_enable <= 1;
                            state <= AUTO_REFRESH;   
                         end 
                       if(word_wr_pulse | word_wr_enable)          
                         begin                    
                            word_wr_enable <= 0;      
                            state <= WORD_WRITE;
                         end                        
                       if(word_rd_pulse | word_rd_enable)       
                         begin                                  
                            word_rd_enable <= 0;                
                            state <= WORD_READ;                
                         end                  
                    end            
     AUTO_REFRESH : begin                      //???? tRC -- 80ns???4?clk                             
                       begin
                          if(word_wr_pulse)
                            word_wr_enable <= 1;
                          else if(word_rd_pulse)     
                            word_rd_enable <= 1;
                       end    
                       num_1 <= num_1 + 1;                                                         
                       if(num_1 == 0)                                    
                         begin                                         
                            sdr_cs  <= 0;                         
                            sdr_ras <= 0;                         
                            sdr_cas <= 0;                         
                            sdr_we  <= 1;                         
                         end                                           
                       else if(num_1 == 1)                               
                         begin                                         
                            sdr_cs  <= 1;                         
                            sdr_ras <= 1;                         
                            sdr_cas <= 1;                         
                            sdr_we  <= 1;                         
                         end                                           
                       else if(num_1 == 7)                              
                         begin                                         
                             num_1 <= 0;                                 
                             state <= IDLE;                          
                         end
                    end 
     WORD_WRITE   : begin
                       if(refresh_pulse)   //??????????????????
                         refresh_enable <= 1;    
                       num_1 <= num_1 + 1;  
                       case(num_1)
                         0 :     begin                                                          
                                    sdr_cs    <= 0;                                             
                                    sdr_ras   <= 0;                                             
                                    sdr_cas   <= 1;                                             
                                    sdr_we    <= 1;                                             
                                    sdr_bank  <= addr_in[21:20];//BANK A                                 
                                    sdr_dqm   <= 2'b00; //?????????????            
                                    `ROW_ADDR <= addr_in[19:8];//12bit                          
                                 end                                                            
                         1 :     begin                
                                    sdr_cs    <= 1;   
                                 end
                         2 :     ;                                    
                         3 :     begin                                                                            
                                    sdr_cs    <= 0;                                                               
                                    sdr_ras   <= 1;                                                               
                                    sdr_cas   <= 0;                                                               
                                    sdr_we    <= 0;                                                               
                                    `A10      <= 1;//?????????????????????????????? 
                                    `COL_ADDR <= addr_in[7:0];                                                    
                                    sdr_data  <= data_in;                                                         
                                 end                                                                              
                         4 :     begin                 
                                    sdr_cs    <= 1;
                                    sdr_ras   <= 1;  
                                    sdr_cas   <= 1;      
                                    sdr_we    <= 1; 
                                    `A10      <= 0;
                                 end                                             
                         5 :     begin
                                    sdr_cs    <= 1;  
                                 end  
                         6 :     begin                                 
                                    num_1 <= 0;
                                    if(refresh_pulse | refresh_enable)
                                      begin
                                         refresh_enable <= 0;
                                         state <= AUTO_REFRESH;
                                      end   
                                    else
                                      state <= IDLE;       
                                 end 
                         default: num_1 <= 0;  
                       endcase
                    end 
     WORD_READ   : begin                                                                                                                
                        if(refresh_pulse)   //??????????????????        
                          refresh_enable <= 1;                                            
                        num_1 <= num_1 + 1;                                               
                        case(num_1) 
                          0 :     begin                                                                                                       
                                     sdr_cs    <= 0;                                    
                                     sdr_ras   <= 0;                                    
                                     sdr_cas   <= 1;                                    
                                     sdr_we    <= 1;                                    
                                     sdr_bank  <= addr_in[21:20];//BANK A               
                                     sdr_dqm   <= 2'b00; //?????????????   
                                     `ROW_ADDR <= addr_in[19:8];//12bit                 
                                  end                                                   
                          1 :     begin                                                 
                                     sdr_cs    <= 1;                                    
                                  end  
                          2 :     ; 
                          3 :     begin                                                                                                        
                                     sdr_cs    <= 0;                                                                 
                                     sdr_ras   <= 1;                                                                 
                                     sdr_cas   <= 0;                                                                 
                                     sdr_we    <= 1;    //?                                                               
                                     `A10      <= 1;//??????????????????????????????   
                                     `COL_ADDR <= addr_in[7:0];                                                                                                               
                                  end
                          4 :    begin                                                                                                        
                                     sdr_cs    <= 1;   
                                     sdr_ras   <= 1;   
                                     sdr_cas   <= 1; 
                                     `A10      <= 0;
                                  end
                          5 :     ; 
                          6 :     begin                                                                         
                                     num_1 <= 0;
                                     if(refresh_pulse | refresh_enable)            
                                       begin                                       
                                          refresh_enable <= 0;                     
                                          state <= AUTO_REFRESH;                   
                                       end                                         
                                     else                                          
                                       state <= IDLE;                              
                                  end  
                         default: num_1 <= 0;                                                                  
                       endcase                        
                    end  
     default:       state <= POWER_UP;                                    
   endcase  
end 



wire sample_en = (state == WORD_READ) && (num_1 == 6);

always @(posedge clk) //对于单字节读写,上下沿都可以      
begin                      
   if(sample_en)
      read_data <= sdram_data; 
end




assign sdram_cs    = sdr_cs;                    
assign sdram_we    = sdr_we;                    
assign sdram_ras   = sdr_ras;                   
assign sdram_cas   = sdr_cas;                   
assign sdram_dqm   = sdr_dqm;                   
assign sdram_scke  = sdr_scke;                  
assign sdram_addr  = sdr_addr;                  
assign sdram_bank  = sdr_bank;  
assign sdram_data  = ~(sdr_we | sdr_cas) ?  sdr_data : 16'hzzzz;    
       
                                                
endmodule   

FPGA主时钟为100M,即以100M时钟操作SDRAM的,故STM32读写SDRAM的平均速率至少可以达到10MBytes/s
此帖出自stm32/stm8论坛

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

小黑屋|手机版|Archiver|电子工程世界 ( 京ICP证 060456

GMT+8, 2017-9-20 10:15 , Processed in 0.223987 second(s), 17 queries , Redis On.

快速回复 返回顶部 返回列表