nemon

【PSoC4】小猫钓鱼

0
阅读(3690)

记得有一篇老课文叫《小猫钓鱼》,内容是这样的:“老猫和小猫一块儿在河边钓鱼。一只蜻蜓飞来了。小猫看见了,放下钓鱼竿,就去捉蜻蜓。蜻蜓飞走了,小猫没捉着,空着手回到河边来。小猫一看,老猫钓着了一条大鱼。一只蝴蝶飞来了。小猫看见了,放下钓鱼竿,又去捉蝴蝶。蝴蝶飞走了,小猫又没捉着,空着手回到河边来。小猫一看,老猫又钓着了一条大鱼。小猫说:“真气人,我怎么一条小鱼也钓不着?” 老猫看了看小猫,说:“钓鱼就钓鱼,不要这么三心二意的。一会儿捉蜻蜓,一会儿捉蝴蝶,怎么能钓着鱼呢?” 小猫听了老猫的话,就一心一意地钓鱼。蜻蜓又飞来了,蝴蝶又飞来了,小猫就象没看见一样。不大一会儿,小猫也钓着了一条大鱼。”

这是一个关于三心二意的故事。古人认为思考是心,所以,三个心,就不能形成一致,两个意念,也就不同一处。精力不集中自然做不好事情。不过,在工程上正相反,提供必要的冗余经常是必要的,比如RAID就是这样。

RAID,即独立磁盘冗余数组(RAID, Redundant Array of Independent Disks),是一种以冗余磁盘的方式获取性能或安全系数的提升的技术,最常见的是兼顾了多方面考虑的RAID5,其主要思想就是增加一个单位的存储介质用于保存其他n个单位的奇偶校验值,这样在出现任1个存储介质失效时,可以继续对付着用,同时由于数据被并行的存储于多个介质上,可以显著提高IO速度。

下面我们就来实现一个n=2的实例。这时将会有3个存储核心,只要其中两个正常工作,就能够继续存取,正所谓“三心二意”。

首先看一下存储,这个是用在creator中用verilog实现的。creator只支持verilog的子集,诸如fork-join,#delay是不支持的,不过对psoc4来讲问题不大,因为他的udb有点少。也正是也因此,这个ram元件只有1位地址、1位输入、1位输出:

对应的源文件RAM1x2.v:


//`#start header` -- edit after this line, do not edit this line
`include "cypress.v"
//`#end` -- edit above this line, do not edit this line
// Generated on 11/15/2013 at 13:12
// Component: RAM1x2
module RAM1x2 (
	Dout,
	addr,
	clock,
	Din,
	RorW
);
//`#start body` -- edit after this line, do not edit this line
	input  clock;
	output  Dout;
	input   addr;
	input   Din;
	input   RorW;
//        Your code goes here
    reg[1:0] memory;
	reg  Dout;
	always @ (posedge clock)//always @(RorW or Din or addr)
	begin
		if(RorW)
            begin
                memory[addr]<=Din;
                //Dout<= #1 1'bx ;
            end
		else 
            begin
                Dout<= memory[addr];
            end
	end
endmodule
//`#start footer` -- edit after this line, do not edit this line
//`#end` -- edit above this line, do not edit this line

下面看一下系统的全貌:


上边用了一个control寄存器和3个pin来模拟由系统装载、卸载存储介质和由硬件插拔判断介质存在的情况,所以是或的关系。然后用查找表来计算是否有2块及以上的介质失效,如果是则out2置高,亮起红色led,并更新状态寄存器。查找表还有个功能就是判断是否应启用备份介质RAM1X2_2参与计算获得数据,这个依靠out0、out1控制mux,写状态寄存器来实现。左边3个控制寄存器用于提供地址、写数据和读写控制信号,写的数据可以有2位,值在[0,3]之间,地址只有1位,值在[0,1]之间。用于写的数据的高位存储于RAM1X2_0,低位存储于RAM1X2_1,高低位异或的结果亦即奇偶校验位存储于RAM1X2_2。如果需要使用RAM1X2_2的数据,还要做异或的逆运算,当然还是异或。左下角uart是用串口来观察数据存取和介质的挂卸的,也是本系统唯一需要编程的部件。觉得最对不起大家的是时钟,因为最后才画,部件间间距又不太好,所以这个线走的……还有Pin_LED_Test_0和Pin_LED_Test_1是为了测试用的。不说了,大家无视就好。

下面是pin的分配:


连接,右边使用了psoc5的uart,左边用3根面包线冒充硬件检测:

实物:

下面解释一下命令,串口界面上有以下几种命令格式(不分大小写):

S 显示3个存储的出错标志寄存器;

Mz、Uz z是取值0~2的数字,此命令表示加载或卸载z号介质;

L 显示当前介质中存储的数据

Gx x取值0或1,此命令用于读取x地址存储的值;

Pxy x含义同上一条,y取值0~3,此命令用于将x地址存储的值更新为y。

下面是一组实验的截图:

再上段代码main.c:


#include <device.h>
#define FLAG_READ  0
#define FLAG_WRITE 1

uint8 get_a_char_from_uart(){
    uint8 c;
    while((c=UART_console_UartGetChar())==0){}
    return c;
}
void print_line_string(char* s){
    UART_console_UartPutString(s);
    UART_console_UartPutCRLF(' ');
}

void show_Storage_State(){
    uint8 i_reg=Control_Reg_DiskError_Read();
    
    UART_console_UartPutString("[0]->");
    UART_console_UartPutCRLF('0'+((i_reg>>(2-0))&0x1));
    
    UART_console_UartPutString("[1]->");
    UART_console_UartPutCRLF('0'+((i_reg>>(2-1))&0x1));
    
    UART_console_UartPutString("[2]->");
    UART_console_UartPutCRLF('0'+((i_reg>>(2-2))&0x1));
}
void show_data_at_address(uint8 iAddr){
    uint8 iData;
    Control_Reg_RW_Write(FLAG_READ);
    Control_Reg_Addr_Write(iAddr);
    CyDelay(100);
    iData=Status_Reg_Data_Read();
    UART_console_UartPutString("ADDR[");
    UART_console_UartPutChar('0'+iAddr);
    UART_console_UartPutString("]=>");
    UART_console_UartPutCRLF('0'+iData);
}
void set_data_at_address(uint8 iAddr,uint8 iData){
    Control_Reg_RW_Write(FLAG_READ);
    Control_Reg_Addr_Write(iAddr);
    Control_Reg_Data_Write(iData);
    Control_Reg_RW_Write(FLAG_WRITE);
    CyDelay(10);
    UART_console_UartPutString("ADDR[");
    UART_console_UartPutChar('0'+iAddr);
    UART_console_UartPutString("]<=");
    UART_console_UartPutCRLF('0'+iData);
    Control_Reg_RW_Write(FLAG_READ);
}

void main()
{
    uint8 c,i_addr,i_reg;

    /* CyGlobalIntEnable; */ /* Uncomment this line to enable global interrupts. */
    UART_console_Start();
    print_line_string("UART Ready.");
    for(;;)
    {
        CyDelay(100);
        c=get_a_char_from_uart();
        UART_console_UartPutChar(c);
        switch(c){
        case 'S':
        case 's':
            print_line_string(" - Storage State:");
            show_Storage_State();
            break;
        case 'R':
        case 'r':
            print_line_string(" - Storage Error Flag:");
            i_reg=Status_Reg_Err_Read();
            UART_console_UartPutString("Flag:=");
            UART_console_UartPutCRLF('0'+i_reg);
            break;
        case 'M':
        case 'm':
            print_line_string(" - Mount Storage:");
            c=get_a_char_from_uart();
            UART_console_UartPutChar(c);
            if(c>='0' && c<='2'){
                i_reg=Control_Reg_DiskError_Read();
                i_addr=c-'0';
                i_addr=0x1<<(2-i_addr);
                i_addr=~i_addr;
                Control_Reg_DiskError_Write(i_reg & i_addr);
                print_line_string(" - Storage Mounted.");
            }else{
                print_line_string(" - Storage Number error!");
            }
            break;
        case 'U':
        case 'u':
            print_line_string(" - UnMount Storage:");
            c=get_a_char_from_uart();
            UART_console_UartPutChar(c);
            if(c>='0' && c<='2'){
                i_reg=Control_Reg_DiskError_Read();
                i_addr=c-'0';
                i_addr=0x1<<(2-i_addr);
                Control_Reg_DiskError_Write(i_reg | i_addr);
                print_line_string(" - Storage UnMounted.");
            }else{
                print_line_string(" - Storage Number error!");
            }
            break;
        case 'L':
        case 'l':
            print_line_string(" - List Storage:");
            i_reg=Status_Reg_Err_Read();
            if(i_reg){
                print_line_string(" Storage Error !");
            }else{
                for(i_addr=0;i_addr<2;i_addr++){
                    show_data_at_address(i_addr);
                }
            }
            break;
        case 'G':
        case 'g':
            print_line_string(" - Stored Data:");
            i_reg=Status_Reg_Err_Read();
            if(i_reg){
                print_line_string(" Storage Error !");
            }else{
                c=get_a_char_from_uart();
                if(c>='0' && c<'2'){
                    i_addr=c-'0';
                    show_data_at_address(i_addr);
                }else{
                    UART_console_UartPutChar(c);
                    print_line_string(" - Address error!");
                }
            }
            break;
        case 'P':
        case 'p':
            print_line_string(" - Set Store:");
            i_reg=Status_Reg_Err_Read();
            if(i_reg){
                print_line_string(" Storage Error !");
            }else{
                c=get_a_char_from_uart();
                UART_console_UartPutChar(c);
                if(c>='0' && c<'2'){
                    print_line_string(" - Address get.");
                    i_addr=c-'0';
                    c=get_a_char_from_uart();
                    if(c>='0' && c<'4'){
                        set_data_at_address(i_addr,c-'0');
                    }else{
                        UART_console_UartPutChar(c);
                        print_line_string(" - Data error!");
                    }
                }else{
                    print_line_string(" - Address error!");
                }
            }
            break;
        default:
            print_line_string(" - Command Error.");
        }
    }
}

/* [] END OF FILE */
看了上边的代码,大家会发现除了对串口交互的支持,全部都是用来存取寄存器的,换句话说,如果真的要做一块raid卡,只要在creator里画图就能实现功能了。下面是项目的rpt文件中“Technology mapping summary”一节,可以看到对udb的消耗相当大,而由于这个实例专注于山寨RAID卡的目标,其他的资源几乎没有用,也许下次博主用psoc4做山寨硬盘的时候会尽量多用一些:
------------------------------------------------------------
Technology mapping summary
------------------------------------------------------------

Resource Type                 : Used : Free :  Max :  % Used
============================================================
Digital domain clock dividers :    0 :    8 :    8 :   0.00%
Analog domain clock dividers  :    0 :    4 :    4 :   0.00%
Pins                          :   10 :   26 :   36 :  27.78%
UDB Macrocells                :   15 :   17 :   32 :  46.88%
UDB Unique Pterms             :   48 :   16 :   64 :  75.00%
UDB Total Pterms              :   51 :      :      : 
UDB Datapath Cells            :    0 :    4 :    4 :   0.00%
UDB Status Cells              :    2 :    2 :    4 :  50.00%
             Status Registers :    2 
UDB Control Cells             :    4 :    0 :    4 : 100.00%
            Control Registers :    4 
Interrupts                    :    0 :   32 :   32 :   0.00%
Comparator/Opamp Fixed Blocks :    0 :    2 :    2 :   0.00%
SAR Fixed Blocks              :    0 :    1 :    1 :   0.00%
CSD Fixed Blocks              :    0 :    1 :    1 :   0.00%
8-bit CapSense IDACs          :    0 :    1 :    1 :   0.00%
7-bit CapSense IDACs          :    0 :    1 :    1 :   0.00%
Temperature Sensor            :    0 :    1 :    1 :   0.00%
Low Power Comparator          :    0 :    2 :    2 :   0.00%
TCPWM Blocks                  :    0 :    4 :    4 :   0.00%
Serial Communication Blocks   :    1 :    1 :    2 :  50.00%
Segment LCD Blocks            :    0 :    1 :    1 :   0.00%