Вы находитесь на странице: 1из 13

2.

(2665)《基于 FPGA 的 I2C 总线控制核设计》P23


I2C 控制核的 VHDL 源码如下:
.附录:VHDL源代码
1. i2c_top 模块逻辑代码
entity i2c_top is
port( eclk: in std_logic;
nReset: in std_logic;
--asram interface signal of EMIF
nAoe: in std_logic;
nAwe: in std_logic;
nAre: in std_logic;
-- Ardy: out std_logic;
nCs: in std_logic;--i2c control core seleted, address decoder output this signal to i2c_top module
-- edat_i:in std_logic_vector(7 downto 0);--EMIF data bus low 8bit in, for test
-- edat_o:out std_logic_vector(7 downto 0); --EMIF data bus low 8bit out, for test
edat :inout std_logic_vector(7 downto 0);
eadd:in std_logic_vector(4 downto 2); --EMIF low address bus
eint: out std_logic;
--i2c interface signal
SCL : inout std_logic;
SDA : inout std_logic );
end entity i2c_top;
signal prer : std_logic_vector(7 downto 0); -- clock prescale register 000wr
signal ctr : std_logic_vector(7 downto 0); -- control register 010wr
signal txr : std_logic_vector(7 downto 0); -- transmit register 011w 101r
signal rxr : std_logic_vector(7 downto 0); -- receive register 011r
signal cr : std_logic_vector(7 downto 0); -- command register 100w 110r
signal sr : std_logic_vector(7 downto 0); -- status register 100
--eclk/8
signal clk8 :std_logic;
-- generate i2c module frequency
process(nReset, eclk)is
begin
if(nReset='0')then
clk8<='0';
div8_cnt<="000";
elsif rising_edge(eclk) then
if( div8_cnt = prer(7 downto 5) )then
clk8<=not clk8;
div8_cnt<="000";
else
div8_cnt<=div8_cnt+'1';
end if;
end if;
end process;

gen_regs: process(nReset, nCs, nAwe,clk8)


begin
if (nReset = '0') then
prer <= (others => '1');-- '0' for stimulate fast; '1' only for real system
ctr <= (others => '0');
txr <= (others => '0');
elsif rising_edge(nAwe) then
if( nCs = '0') then --nAwe='0'
case eadd is
when "000" => prer( 7 downto 0) <= edat;--edat_i;
when "010" => ctr <= edat;--edat_i;
when "011" => txr <= edat;--edat_i;--data write to slave
-- illegal cases, for simulation only
when others =>
prer <=prer;
ctr <= ctr;
txr <= txr;
end case;
end if;
end if;
end process gen_regs;
-- decode control register
core_en <= ctr(7);--i2c core enable bit
ien <= ctr(6);--interrupt enable bit
-- generate command register
gen_cr: process(nReset, nAwe, clk8, core_en, nCs,done)
begin
if (nReset = '0' or done='1') then
cr <= (others => '0');
elsif rising_edge(nAwe) then
if ( nCs= '0') then --nAwe = '0' and
if ( core_en = '1' and eadd = "100" ) then
-- only take new commands when i2c core enabled
-- pending commands are finished
cr <= edat;--edat_i;
end if;
else
cr(2 downto 1) <= "00";--(others => '0'); -- reserved bits, always '0'
cr(0) <= '0'; -- clear IRQ_ACK bit
end if;
end if;
end process gen_cr;
-- decode command register
start_r <= cr(7);
stop_r <= cr(6);
rd_r <= cr(5);
wr_r <= cr(4);
ack_r <= cr(3);-- '0'表示确认
iack_r <= cr(0);-- 中断响应位
assign_edato : process(nCs,nAre,nAoe,eadd,prer, ctr, rxr, sr, txr, cr)
variable dat_o:std_logic_vector(7 downto 0);
begin
if(nCs = '0' and nAre ='0' and nAoe='0')then
case eadd is
when "000" => dat_o := prer(7 downto 0);
when "010" => dat_o := ctr;
when "011" => dat_o := rxr; -- write is transmit register TxR
when "100" => dat_o := sr; -- write is command register CR
when "111" => dat_o := "10011101";--(others => '0'); for test
when others => dat_o := "ZZZZZZZZ";
end case;
else
dat_o := "ZZZZZZZZ";
end if;
edat <= dat_o;
end process assign_edato;
-- interrupt request signal
gen_irq: process (clk8, nReset)
begin
if (nReset = '0') then
int <= '0';
elsif (clk8'event and clk8 = '1') then
-- interrupt signal is only generated when IEN (interrupt enable bit) is set
int <= irq_flag and ien;
end if;
end process gen_irq;
eint<= int when (ien = '1') else 'Z';--利用中断使能信号 ien 实现 EINT 的共享
end architecture rtl;

2. i2c 时序状态机模块代码
entity i2c_core is
port ( clk : in std_logic;
nReset : in std_logic;
cmd_ack : out std_logic;
clk_cnt : in std_logic_vector(4 downto 0);
cmd : in std_logic_vector(2 downto 0);
Din : in std_logic;
Dout : out std_logic;
busy : out std_logic;
SCL : inout std_logic;
SDA : inout std_logic );
end entity i2c_core;
architecture structural of i2c_core is
begin
slave_wait <= '1' when ((SCLo = '1') and (SCL = '0')) else '0';
-- generate clk enable signal
gen_clken: process(clk, nReset)
begin
if (nReset = '0') then
cnt <= (others => '0');
clk_en <= '1'; --'0';
elsif (clk'event and clk = '1') then
if (cnt = "00000") then
clk_en <= '1';
cnt <= clk_cnt;
else
if (slave_wait = '0') then
cnt <= cnt -'1';
end if;
clk_en <= '0';
end if;
end if;
end process gen_clken;
-- generate statemachine
nxt_state_decoder : process (clk, nReset, state, cmd, SDA, din)
variable nxt_state : cmds;
variable icmd_ack, ibusy : std_logic;
begin
nxt_state := state;
icmd_ack := '0'; -- default no acknowledge
ibusy := '1'; -- default busy
store_sda <= '0';
if (nReset = '0') then
state <= idle;
cmd_ack <= '0';
busy <= '0';
Dout <= '0';
elsif (clk'event and clk = '1') then
if (clk_en = '1') then
state <= nxt_state;
busy <= ibusy;
if (store_sda = '1') then
Dout <= SDA;
end if;
end if;
cmd_ack <= icmd_ack and clk_en;
end if;
case (state) is
when idle =>
case cmd is
when CMD_START =>
nxt_state := start_a;
icmd_ack := '1'; -- command completed
when CMD_STOP =>
nxt_state := stop_a;
icmd_ack := '1';
when CMD_WRITE =>
nxt_state := wr_a;
icmd_ack := '1';
when CMD_READ =>
nxt_state := rd_a;
icmd_ack := '1';
when others =>
nxt_state := idle;
icmd_ack := '1';
ibusy := '0';
end case;
when start_a =>
nxt_state := start_b;
when start_b =>
nxt_state := start_c;
when start_c =>
nxt_state := start_d;
when start_d =>
nxt_state := start_e;
when start_e =>
nxt_state := start_f;
when start_f =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle
when stop_a =>
nxt_state := stop_b;
when stop_b =>
nxt_state := stop_c;
when stop_c =>
nxt_state := stop_d;
when stop_d =>
nxt_state := stop_e;
when stop_e =>
nxt_state := stop_f;
when stop_f =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle
when rd_a =>
nxt_state := rd_b;
when rd_b =>
nxt_state := rd_c;
when rd_c =>
nxt_state := rd_d;
when rd_d =>
nxt_state := rd_e;
store_sda <= '1';
when rd_e =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle
when wr_a =>
nxt_state := wr_b;
when wr_b =>
nxt_state := wr_c;
when wr_c =>
nxt_state := wr_d;
when wr_d =>
nxt_state := wr_e;
when wr_e =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle
end case;
end process nxt_state_decoder;
SCL <= '0' when (SCLo = '0') else 'Z';
SDA <= '0' when (SDAo = '0') else 'Z';
end architecture structural;
3 .i2c 命令状态机模块代码

entity i2c is
port ( clk : in std_logic;
ena : in std_logic;
nReset : in std_logic;
cmd_ack : out std_logic;
ack_out : out std_logic;
busy :out std_logic;
clk_cnt : in std_logic_vector(4 downto 0);
start,stop,read,write,ack_in : in std_logic;
Din : in std_logic_vector(7 downto 0);
Dout : out std_logic_vector(7 downto 0);
SCL : inout std_logic;
SDA : inout std_logic );
end entity i2c;
architecture structural of i2c is
signal core_cmd : std_logic_vector(2 downto 0);
signal core_ack, core_busy, core_txd, core_rxd : std_logic;
signal sr : std_logic_vector(7 downto 0); -- 8bit shift register
signal shift, ld ,go, host_ack: std_logic;
begin
ack_out <= core_rxd;
go <= ( read or write) and not host_ack;
-- sgo <= go;--for simulation
-- assign Dout output to shift-register (7 downto 0)
Dout <= sr;
-- generate host-command-acknowledge
cmd_ack <= host_ack;
busy<=core_busy;
-- generate shift register
shift_register: process(clk)
begin
if (clk'event and clk = '1') then
if (ld = '1') then
sr <= din;--load data to sr
elsif (shift = '1') then
sr <= (sr(6 downto 0) & core_rxd);--shift to left a bit
end if;
end if;
end process shift_register;

statemachine : block
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
signal state : states;
signal dcnt : unsigned(2 downto 0);-- use to indicate 8 databits of a byte
begin
nxt_state_decoder: process(clk, nReset, state,dcnt, core_txd, core_cmd, go, start, read, core_ack, sr(7),
ack_in, stop)
variable nxt_state : states;
variable idcnt : unsigned(2 downto 0);--use to 指示字节的 8 个节拍
variable ihost_ack : std_logic;
variable icore_cmd : std_logic_vector(2 downto 0);
variable icore_txd : std_logic;-- store transmit data bit
variable ishift, iload : std_logic;
begin
-- 8 databits (1byte) of data to shift-in/out
idcnt := dcnt;
-- no acknowledge (until command complete)
ihost_ack := '0';
-- keep current databit transmit to i2c_core
icore_txd := core_txd;
icore_cmd := core_cmd;
ishift := '0';
iload := '0';
nxt_state := state; -- keep current state;
if (nReset = '0') then
core_cmd <= CMD_NOP;
core_txd <= '0';
shift <= '0';
ld <= '0';
dcnt <= "111";
host_ack <= '0';
state <= st_idle;
elsif (clk'event and clk = '1') then
if (ena = '1') then
state <= nxt_state;
dcnt <= idcnt;
shift <= ishift;
ld <= iload;
core_cmd <= icore_cmd;
core_txd <= icore_txd;
host_ack <= ihost_ack;
end if;
end if;
-- state machine
case state is
when st_idle => -- States change in st_idle.
if (go = '1') then
if (start = '1') then
nxt_state := st_start;
icore_cmd := CMD_START;
elsif (read = '1') then --sequenc read
nxt_state := st_read;
icore_cmd := CMD_READ;
idcnt := "111"; --set 8 databits
else --sequent write
nxt_state := st_write;
icore_cmd := CMD_WRITE;
idcnt := "111"; --set 8 databits
iload := '1'; --allow to load data, which will be sent out!
end if;
end if;
when st_start =>
if (core_ack = '1') then --has already interpretted the start command
if (read = '1') then --read follow start
nxt_state := st_read;
icore_cmd := CMD_READ;
idcnt := "111";
else --write follow start
nxt_state := st_write;
icore_cmd := CMD_WRITE;
idcnt := "111";
iload := '1';
end if;
end if;
when st_write =>
if (core_ack = '1') then --has already interpretted the write command
idcnt := dcnt -1; -- count down Data_counter
icore_txd := sr(7); --send out the bit7 to core
if (dcnt = 0) then --already send 8 bits data
nxt_state := st_ack; --change state to st_ack
icore_cmd := CMD_READ; --read the ack bit from slave
else
ishift := '1';
end if;
end if;
when st_read =>
if (core_ack = '1') then
idcnt := dcnt -1; -- count down Data_counter
ishift := '1';
if (dcnt = 0) then --already read 8 bits data
nxt_state := st_ack; -- change state to st_ack
icore_cmd := CMD_WRITE; --write a ack bit to the slave
icore_txd := ack_in; --发送确认位到 Slave
end if;
end if;
when st_ack => --8bits read or write command has completed, wait for
acknowledge.
if (core_ack = '1') then
ihost_ack := '1';
ishift := '1'; --shift the 9 bit= slave ack bit.
if (stop = '1') then
nxt_state := st_stop;
icore_cmd := CMD_STOP;
else
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end if;
end if;
when st_stop =>
if (core_ack = '1') then
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end if;
when others => -- illegal states
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end case;
end process nxt_state_decoder;
end block statemachine;
end architecture structural;

. 基于 RAM 的文件系统的实现 vxworks

如果的系统上安装有硬盘,则在 BSP 中装载你的硬盘驱动即可。如果没有,建议建立基于 RAM 的


文件系统。建立 RAM 文件系统的方式如下:

#ifndef RAMDISK_VERSION
#define RAMDISK_VERSION '1.0 built by tiefeng@vip.sina.com'
#endif // RAMDISK_VERSION

#include <vxWorks.h>
#include <stdio.h>
#include <ramDrv.h>
#include <iosLib.h>
#include <dosFsLib.h>
#include <alloc.h>
/**********************************************************************

Function: Create a ram disk device
Parameters:
name -> device name, such as 'ramdisk0:'.
size -> block device size.
Returned:
The actualy disk size. Or ERROR.

**********************************************************************/

STATUS CreateRamDisk(char * name,int size)
{
int nBlock = NULL 
BLK_DEV * pBlkDev = NULL 
DOS_VOL_DESC * pVolDesc = NULL 

// the disksize should be integral multiple of the blocksize.

size = size - size%512 
nBlock = size/512 

// You can simultaneously open 20 files

dosFsInit(20) 

// Create a ram-disk.
// The base address is the return value of alloc.
// The block size is 512.
// nBlock blocks per track
// Total nBlock blocks.
// The base address offset is 0.

pBlkDev = ramDevCreate(0,512,nBlock,nBlock,0) 
if (NULL==pBlkDev)
{
fprintf(stderr,'Can not create ram block device.\n') 
return ERROR 
}

// Make DOSFS by a ram block device.
pVolDesc = dosFsMkfs(name,pBlkDev) 
if (NULL==pVolDesc)
{
fprintf(stderr,'Can not create ram-dos-fs.\n') 
return ERROR 
}

// The size is actualy disk size.

return size 
}

/**********************************************************************

Function: Delete a ram disk device
Parameters:
name -> device name, such as 'ramdisk0:'.
Returned:
Return OK if the device is removed successfuly.
Otherwise return ERROR.

**********************************************************************/

STATUS DeleteRamDisk(char * name)
{
DEV_HDR * pDevHdr = NULL 

// Find ram-disk device by name

if ( NULL==(pDevHdr=iosDevFind(name,NULL)) )
{
fprintf(stderr,'Can not find device (%s).\n',name) 
return ERROR 
}

// Delete the device and free the alloced memory

iosDevDelete(pDevHdr) 
free(pDevHdr) 

return OK 
}
/**********************************************************************

Function: Create a ram disk device & set is as default path.
Parameters:
name -> device name, such as 'ramdisk0:'.
size -> block device size.
Returned:
The actualy disk size. Or ERROR.

**********************************************************************/

STATUS InitRamFsEnv(char * name,int size)
{
STATUS iReturn = CreateRamDisk(name,size) 

if (ERROR!=iReturn) ioDefPathSet(name) 

return iReturn 
}

Вам также может понравиться