【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%
