【PSoC4】小猫钓鱼
0赞记得有一篇老课文叫《小猫钓鱼》,内容是这样的:“老猫和小猫一块儿在河边钓鱼。一只蜻蜓飞来了。小猫看见了,放下钓鱼竿,就去捉蜻蜓。蜻蜓飞走了,小猫没捉着,空着手回到河边来。小猫一看,老猫钓着了一条大鱼。一只蝴蝶飞来了。小猫看见了,放下钓鱼竿,又去捉蝴蝶。蝴蝶飞走了,小猫又没捉着,空着手回到河边来。小猫一看,老猫又钓着了一条大鱼。小猫说:“真气人,我怎么一条小鱼也钓不着?” 老猫看了看小猫,说:“钓鱼就钓鱼,不要这么三心二意的。一会儿捉蜻蜓,一会儿捉蝴蝶,怎么能钓着鱼呢?” 小猫听了老猫的话,就一心一意地钓鱼。蜻蜓又飞来了,蝴蝶又飞来了,小猫就象没看见一样。不大一会儿,小猫也钓着了一条大鱼。”
这是一个关于三心二意的故事。古人认为思考是心,所以,三个心,就不能形成一致,两个意念,也就不同一处。精力不集中自然做不好事情。不过,在工程上正相反,提供必要的冗余经常是必要的,比如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%