I2C master for tmp007 sensor module - verilog

I'm trying to create an I2C protocol in verilog to read data from a sensor (TMP007)then show the data received using led but to no avail. I've been trying to put led (eg. LED_GREEN[2] =1;) in the state to test the flow of the state. Only the LED_GREEN1 and LED_GREEN[0] are lighten up. So I guess the problem does occur in STATE_WACK2. Anyone can help?
module tmpi2c(
input wire clk,
input wire reset,
inout reg i2c_sda,
output wire i2c_scl,
output reg [17:0] LED_RED, // LED Red[17:0]
output reg [7:0] LED_GREEN
);
// write to device address 0x40, 0x01h
localparam STATE_IDLE = 0;
localparam STATE_START = 1;
localparam STATE_ADDR = 2;
localparam STATE_RW = 3;
localparam STATE_WACK = 4;
localparam STATE_DATA = 5;
localparam STATE_WACK2 = 6;
localparam STATE_ADDR2 = 7;
localparam STATE_RW2 = 8;
localparam STATE_WACK3 = 9;
localparam STATE_READ = 10;
localparam STATE_WACK4 = 11;
localparam STATE_READ2 = 12;
localparam STATE_WACK5 = 13;
localparam STATE_STOP = 14;
localparam STATE_DISPLAY = 15;
reg enable; //(r=1, w=0)
reg clki2c = 0;
reg [9:0]counter = 0; // 10-bit counter size
reg [9:0] timer = 0;
reg [7:0] state;
reg [6:0] addr;
reg [7:0] data;
reg [7:0] count;
reg [15:0] value =0;
reg [4:0] ge,shi,bai;
reg i2c_scl_enable =0;
assign i2c_scl = (i2c_scl_enable == 0) ? 1 : ~clki2c;
reg i2c_sda_en;
wire i2c_sda_in = i2c_sda ;
// counter size calculation according to input and output frequencies
parameter sys_clk = 50000000; // 50 MHz system clock
//parameter clk_out = 400000; // 0.4 MHz clock output
parameter clk_out = 200000; // 0.2 MHz clock output
//parameter clk_out = 1; // 1Hz clock output
parameter max = sys_clk / (2*clk_out); // max-counter size
//clock divider from 50Mhz to 0.4Mhz
always#(posedge clk or posedge reset)
begin
if(reset) begin
counter <=0;
clki2c <= 0;
end
else begin
if (counter < max) begin
counter <= counter + 1'd1;
end
else begin
counter <= 0;
clki2c <= ~clki2c;
end
end
end
//end clock divider
always#(posedge clki2c) begin
if (!i2c_sda_en) begin i2c_sda = i2c_sda ;
end else begin
i2c_sda = 1'bz;
end
if (reset == 1)
begin
state <= 0;
//i2c_sda <= 1;
//i2c_scl <= 1;
i2c_sda_en <= 1;// i2c_sda ==z;
addr <= 7'h40;
count <= 8'd0;
data <= 8'h01;
LED_RED[17:0] = 0;
LED_GREEN[7:0] = 0;
end
else begin
case(state)
STATE_IDLE: begin //idle
state <= STATE_START;
end
STATE_START: begin //start
i2c_sda_en <= 0;
state <=STATE_ADDR;
count <= 6;
end
STATE_ADDR: begin //msb address bit
LED_GREEN[0] =1;
i2c_sda <= addr[count];
if (count ==0) state <= STATE_RW;
else count <= count -1;
end
STATE_RW: begin
i2c_sda <=0; //write here
state <=STATE_WACK;
end
STATE_WACK: begin
i2c_sda_en <= 1;
if(i2c_sda_in==1)
begin
state <= STATE_WACK;
end
else
begin
state <= STATE_DATA;
end
count <= 7 ;
i2c_sda_en <= 0;
end
STATE_DATA: begin
LED_GREEN[1] =1;
i2c_sda <= data[count];
if (count == 0) state <= STATE_WACK2;
else count <= count -1;
end
STATE_WACK2: begin
i2c_sda_en <= 1;
if(i2c_sda_in==1)
begin
state <= STATE_WACK2;
end
else
begin
state <= STATE_ADDR2;
//LED_GREEN[1] =1;
end
count <= 6;
i2c_sda_en <= 0;
end
STATE_ADDR2: begin
LED_GREEN[2] =1;
i2c_sda <= addr[count];
if (count ==0) state <= STATE_RW2;
else count <= count -1;
end
STATE_RW2: begin
i2c_sda <=1; //read here
state <=STATE_WACK3;
end
STATE_WACK3: begin
i2c_sda_en <= 1;
if(i2c_sda_in==1)
begin
state <= STATE_WACK2;
end
else
begin
state <= STATE_READ;
end
count <= 15;
//i2c_sda_en <= 0;
end
STATE_READ: begin
LED_GREEN[3] =1;
value[count] <= i2c_sda_in;
if (count == 8) state<= STATE_WACK4;
else count <= count -1;
end
STATE_WACK4: begin
i2c_sda_en <= 0;
i2c_sda <=1; //Master should leave SDA high to terminate a single-byte read operation.
state <= STATE_READ2;
count <= 7;
i2c_sda_en <= 1;
end
STATE_READ2: begin
LED_GREEN[4] =1;
value[count] <= i2c_sda_in;
if (count == 0) state<= STATE_WACK5;
else count <= count -1;
end
STATE_WACK5: begin
i2c_sda_en <= 0;
i2c_sda <=1; //Master should leave SDA high to terminate a two-byte read operation.
state <= STATE_STOP;
end
STATE_STOP: begin
//i2c_sda <=1;
state <= STATE_DISPLAY;
end
STATE_DISPLAY: begin
LED_RED[17] = value[15];
LED_RED[16] = value[14];
LED_RED[15] = value[13];
LED_RED[14] = value[12];
LED_RED[13] = value[11];
LED_RED[12] = value[10];
LED_RED[11] = value[9];
LED_RED[10] = value[8];
LED_RED[9] = value[7];
LED_RED[8] = value[6];
LED_RED[7] = value[5];
LED_RED[6] = value[4];
LED_RED[5] = value[3];
LED_RED[4] = value[2];
LED_RED[2] = value[0];
LED_RED[3] = value[1];
//display delay
if (timer < 100000) timer <= timer+1;
else timer <= 0;
state <= STATE_IDLE;
end
endcase
end
end
endmodule

Related

Sync RAM related

I am trying to simulate the following code for an synchronous ram in Verilog.
When I am trying to write in a specific address, dataOut is not coming the way I was expecting. It is skipping 1 address while reading data in the specified address.
Can anyone tell me the problem?
Here is GtkWave simulation result:
module ram
# (parameter ADDR_WIDTH = 4,
parameter DATA_WIDTH = 10,
parameter DEPTH = 1 << ADDR_WIDTH
)
( input clk,
input [ADDR_WIDTH-1:0] addr,
input [DATA_WIDTH-1:0] dataIn,
input enable,
input write,
input read,
input resetRam,
output[DATA_WIDTH-1:0] dataOut
);
reg [DATA_WIDTH-1:0] tmp_data;
reg [DATA_WIDTH-1:0] mem [DEPTH-1:0];
//reset
always #(posedge clk) begin
if(enable & resetRam) begin
for (integer i = 0; i < 2**ADDR_WIDTH; i = i + 1)
begin
mem[i] = {DATA_WIDTH{1'b0}};
end
end
end
//write
always # (posedge clk) begin
if (enable & write & !read)
mem[addr] <= dataIn;
end
//read
always # (posedge clk) begin
if (enable & !write & read)
tmp_data <= mem[addr];
end
assign dataOut = enable & read & !write ? tmp_data : 'hz || enable & resetRam ? 10'b0 : 'hz;
endmodule
module ram_tb;
parameter ADDR_WIDTH = 4;
parameter DATA_WIDTH = 10;
parameter DEPTH = 1 << ADDR_WIDTH;
reg clk;
reg enable;
reg write;
reg read;
reg resetRam;
reg [ADDR_WIDTH-1:0] addr;
wire [DATA_WIDTH-1:0] dataIn;
wire [DATA_WIDTH-1:0] dataOut;
reg [DATA_WIDTH-1:0] tb_data;
ram #(.DATA_WIDTH(DATA_WIDTH)) iram(
.clk(clk),
.addr(addr),
.dataIn(dataIn),
.enable(enable),
.write(write),
.read(read),
.resetRam(resetRam),
.dataOut(dataOut)
);
always #10 clk = ~clk;
assign dataIn = !read ? tb_data : 'hz ;
initial begin
$monitor("addrs = %b resetRam=%b Write = %b read=%b dataIn = %b dataOut = %b", addr,resetRam,write,read,dataIn,dataOut);
$dumpfile("ram_tb.vcd");
$dumpvars(0,ram_tb);
{clk, enable, write, addr, tb_data, read,resetRam} <= 0;
// //writing all the adrress with random value
// for (integer i = 0; i < DEPTH; i= i+1) begin
// #(posedge clk) addr <= i; write = 1; enable =1; read = 0; tb_data <= $random;
// end
// //reading them
// for (integer i = 0; i < DEPTH; i= i+1) begin
// #(posedge clk) addr = i; write = 0; enable = 1; read = 1;
// end
//Writing at specific address
#(posedge clk) addr = 4'b1000; write = 1; enable =1; read = 0; tb_data <= $random;
#(posedge clk) addr = 4'b1111; write = 1; enable =1; read = 0; tb_data <= $random;
#(posedge clk) addr = 4'b1001; write = 1; enable =1; read = 0; tb_data <= $random;
#(posedge clk) addr = 4'b0001; write = 1; enable =1; read = 0; tb_data <= $random;
//reading them
#(posedge clk) addr = 4'b1000;write = 0; enable =1; read = 1;
#(posedge clk) addr = 4'b1111;write = 0; enable =1; read = 1;
#(posedge clk) addr = 4'b1001;write = 0; enable =1; read = 1;
#(posedge clk) addr = 4'b0001;write = 0; enable =1; read = 1;
// //reset memory
// for (integer i = 0; i < DEPTH; i= i+1) begin
// repeat (1) #(posedge clk) addr <= i; enable <= 1; resetRam <=1;
// end
#200 $finish;
end
endmodule
//iverilog -o ram_tb.vpp ram.v
//vvp ram_tb.vpp
You have a race condition. You should use nonblocking assignments (<=) in your design and testbench for all synchronous signals.
In the design, change:
mem[i] = {DATA_WIDTH{1'b0}};
to:
mem[i] <= {DATA_WIDTH{1'b0}};
In the testbench, use:
//Writing at specific address
#(posedge clk) addr <= 4'b1000; write <= 1; enable <=1; read <= 0; tb_data <= $random;
#(posedge clk) addr <= 4'b1111; write <= 1; enable <=1; read <= 0; tb_data <= $random;
#(posedge clk) addr <= 4'b1001; write <= 1; enable <=1; read <= 0; tb_data <= $random;
#(posedge clk) addr <= 4'b0001; write <= 1; enable <=1; read <= 0; tb_data <= $random;
//reading them
#(posedge clk) addr <= 4'b1000;write <= 0; enable <=1; read <= 1;
#(posedge clk) addr <= 4'b1111;write <= 0; enable <=1; read <= 1;
#(posedge clk) addr <= 4'b1001;write <= 0; enable <=1; read <= 1;
#(posedge clk) addr <= 4'b0001;write <= 0; enable <=1; read <= 1;
With the above changes, I get your expected output with iverilog on edaplayground.

Verilog synthesis is giving me an error that I don't understand

I am getting this error when synthesizing my code, but I don't know what it means. It reads:
Error- net "Count[0] or a directly connected net is driven by more
than one source and not all drivers are three state.
It says the same errors for vectors count[0] - count[4] as well as for my load and k values. The code is my representation of an SPI Master. The SPI master has an instantiation of a shift register that is used to push out information.
module SPIMaster(output reg SCLK, CS, MOSI,
input EN, CLK, MISO,
input [7:0] m_data);
wire master_out;
reg [4:0] count;
wire [7:0] data_buff;
wire SCLK1;
reg master_in, c_sw, k, state, load;
shiftReg register_out (master_out, data_buff, load, (~SCLK), master_in, m_data);
assign SCLK1 = (~c_sw) | CLK;
always#(posedge CLK) begin
if(state) begin
if (k == 1) begin
state <= 0;
c_sw <= 0;
CS <= 1;
count <= 0;
k <= 0;
load <= 0;
end
else begin
state <= 1;
c_sw <= 1;
CS <= 0;
end
end
else begin
if (EN == 1) begin
state <= 1;
c_sw <= 1;
CS <= 0;
count <= 0;
k <= 0;
load <= 1;
end
else begin
state <= 0;
c_sw <= 0;
CS <= 1;
count <= 0;
k <= 0;
load <= 0;
end
end
end
always#(posedge SCLK1) begin
if (CS == 0) master_in <= MISO;
if (count == 7) begin
load <= 0;
end
else if (count == 15)begin
load <= 0;
end
else begin
load <= 1;
end
end
always#(negedge SCLK1) begin
if (count == 23) k <= 1;
else k <= 0;
if (CS == 0) begin
MOSI <= master_out;
count <= count + 1;
end
end
endmodule
Your code does not adhere to good synthesis coding practices because you assign to count from 2 different always blocks and those 2 blocks are triggered by different clock signals. You should make all assignments to count from the same always block.
The same is true of load and k.

Illegal reference to net rddata in FIFO

The below code is for a FIFO. It is showing an error as illegal reference to net datatype as rddata at line 38 in tb (highlighted by adding a comment "//error line").
Why do I get this error?
module fifo(clk,rst,error,empty,full,rddata,wrdata,wr_en,rd_en);
parameter WIDTH = 8;
parameter DEPTH = 16;
input clk,rst,rd_en,wr_en;
input [WIDTH-1:0]wrdata;
output reg [WIDTH-1:0]rddata;
output reg empty,full,error;
reg [WIDTH-1:0]mem[DEPTH-1:0];
reg [3:0]rd_ptr;
reg [3:0]wr_ptr;
reg wr_toggle,rd_toggle;
integer i;
always#(posedge clk)
begin
if(rst==1)
begin
empty = 1;
full = 0;
error = 0;
rd_ptr = 0;
wr_ptr = 0;
wr_toggle = 0;
rd_toggle = 0;
for(i=1;i<DEPTH;i=i+1)
begin
mem[i] = 0;
end
end
else
begin
if(wr_en ==1)begin
if(full==1)begin
$display("ERROR:Writing to full FIFO");
error = 1;
end
else
begin
mem[wr_ptr] = wrdata;
if(wr_ptr == DEPTH-1)begin
wr_toggle = ~wr_toggle;
wr_ptr = 0;
end
else begin
wr_ptr = wr_ptr + 1;
end
end
end
if(rd_en ==1)begin
if(empty==1)begin
$display("ERROR:REading from EMPTY FIFO");
error = 1;
end
end
else
begin
mem[rd_ptr] = rddata;
if(rd_ptr == DEPTH-1)begin
rd_toggle = ~rd_toggle;
rd_ptr = 0;
end
else begin
rd_ptr = rd_ptr + 1;
end
end
end
end
always#(wr_ptr or rd_ptr)
begin
full = 0;
empty = 0;
if(wr_ptr == rd_ptr && wr_toggle == rd_toggle)begin
empty = 1;
full = 0;
end
if(wr_ptr == rd_ptr && wr_toggle != rd_toggle)begin
empty = 0;
full = 1;
end
end
endmodule
//TEST BENCH
`include "fifo.v"
module tbfifo();
parameter WIDTH = 8;
parameter DEPTH = 16;
reg clk,rst,rd_en,wr_en;
reg [WIDTH-1:0]wrdata;
wire [WIDTH-1:0]rddata;
wire empty,full,error;
integer i;
fifo_buff dut (clk,rst,error,empty,full,rddata,wrdata,wr_en,rd_en);
initial
begin
clk = 0;
forever #5 clk = ~clk;
end
initial
begin
rst = 1;
repeat(2) #(posedge clk);
rst = 0;
for(i=0;i<DEPTH;i=i+1)begin
#(posedge clk);
wr_en = 1;
wrdata = $random;
end
#(posedge clk);
wr_en = 0;
wrdata= 0;
for(i=0;i<DEPTH;i=i+1)begin
#(posedge clk);
rd_en = 1;
rddata <= $random; //error line
end
#(posedge clk);
rd_en = 0;
#100;
$finish;
end
endmodule
rddata is an output port of the fifo_buff module. In the testbench, there is a wire named rddata which connects to the fifo instance.
The problem is that the testbench then tries to drive the signal:
rddata <= $random; //error line
That is illegal. You can not make a procedural assignment (inside an initial block, for example) to a wire. And, you should not try to drive that signal from the testbench since it is already driven by the module instance, because that would results in multiple drivers (contention). You must remove this line.
for (i=0; i<DEPTH; i=i+1) begin
#(posedge clk);
rd_en = 1;
end
#(posedge clk);
rd_en = 0;
Typically, you would monitor an output signal in the testbench (display its value or compare it against a reference model). This is usually done in a separate process (always block, for example) from the input driving process.

inout verilog protocol I2C

I'm creating the I2C protocol in verilog to read data from a sensor (BMP180), AS you know, the sensor sends me a bit of ack recognition. How do I use the inout i2c_sda port to send and how do I receive.
As delivery and receipt i2c_sda the same line, if my variable is declared of type inout.
module stepPrueba(
input wire clk1,
input wire reset,
input wire start,
inout i2c_sda,
inout i2c_scl,
output wire ready,
output reg led1,
output reg led2
);
reg i2c_scl_out;
assign i2c_scl1= (i2c_scl_out == 1'b0) ? 1'b0 : 1'bz;
wire i2c_scl_in = i2c_scl;
assign i2c_scl = (i2c_scl_enable == 0) ? i2c_scl1 : clk1;
reg clk;
assign clk1 = (clk == 1)? 1'bz:1'b0;
reg i2c_sda_out;
assign i2c_sda = (i2c_sda_out == 1'b0) ? 1'b0 : 1'bz;
wire i2c_sda_in = i2c_sda ;
reg [6:0] addr;
reg [7:0] data;
reg enable; //(read=1, write=0)
reg datas;
reg enable2; //(read=1, write = 0)
reg [7:0] state;
reg [7:0] count;
reg i2c_scl_enable = 0;
reg [6:0] saved_addr;
reg [7:0] saved_data;
//goal es escribir al dispositivo direccion 0X55, 0Xaa
localparam STATE_IDLE = 0;
localparam STATE_START = 1;
localparam STATE_ADDR =2;
localparam STATE_RW = 3;
localparam STATE_WACK = 4;
localparam STATE_DATA = 5;
localparam STATE_WACK2 = 6;
localparam STATE_STOP = 7;
always#(posedge clk)
begin
//enable2 <= 0; //i2c_scl==zetas & c_lectura=z;
if(reset == 1)
begin
i2c_scl_out<=1;
i2c_scl_enable <= 0;
end
else
begin
if((state == STATE_IDLE) || (state == STATE_START) )
begin
//i2c_scl_enable <= 0; //dats == 1 --> ztas == z
i2c_scl_out<=1;
i2c_scl_enable <= 0;
end
else
begin
i2c_scl_enable <= 1; // dats==clk;
clk<=clk1;
end
end
end
always#(posedge clk)
begin
if(reset == 1)
begin
led1 <=0;
led2 <=0;
state <=0;
i2c_sda_out <= 1;// i2c_sda ==z;
addr <= 7'b1110111; // direccion del sensor
count <= 8'd0;
data <= 8'b11110100; //direccion interna PRESION
end
else //reset ==0
begin
case (state)
STATE_IDLE:
begin //idle
//datas <= 1; //zetas==z
i2c_scl_out<=1;
i2c_scl_enable <= 0;
i2c_sda_out <= 1;
if(start)
begin
state <= STATE_START;
saved_addr <= addr;
saved_data <= data;
// reg i2c_scl_out;
// assign i2c_scl1= (i2c_scl_out == 1'b0) ? 1'b0 : 1'bz;
// wire i2c_scl_in = i2c_scl;
// assign i2c_scl = (i2c_scl_enable == 0) ? i2c_scl1 : ~clk;
end
else
begin
state <= STATE_IDLE;
end
end
STATE_START:
begin // start
//enable <= 0; // lectura==z; --> i2c_sda==zetas
i2c_sda_out <= 0;
//datas <= 0; // zetas==0
state<= STATE_ADDR;
count <= 6;
end
STATE_ADDR:
begin //msb addres bit
//enable <= 0; // lectura==z; --> i2c_sda==zetas
i2c_sda_out <= saved_addr[count]; // datas ==0 --> zetas==0 || datas==1 --> zetas==z
if (count == 0)
begin
state <= STATE_RW;
end
else
begin
count <= count - 1;
end
end
STATE_RW:
begin
//enable <= 0; //enable==0 --> i2c_sda==zetas
i2c_sda_out <= 0;//datas <= 0;
state <= STATE_WACK;
end
STATE_WACK:
begin
//enable <= 1; //enable==1 lee i2c_sda==z & lectura==i2c_sda
//enable <= 0;
//if(APA)
if(i2c_sda_in==1)
begin
state <= STATE_IDLE;
end
else
begin
state <= STATE_DATA;
led1 <= 1;
end
count <= 7;
end
STATE_DATA:
begin
//enable <= 0;
i2c_sda_out <= saved_data[count];
if(count ==0)
begin
state <= STATE_WACK2;
end
else
begin
count <= count - 1;
end
end
STATE_WACK2:
begin
//enable <= 1;
if(i2c_sda_in ==1)
begin
state <= STATE_IDLE;
end
else
begin
state <= STATE_STOP;
led2 <= 1;
end
end
STATE_STOP:
begin
//enable <= 0;
i2c_sda_out <= 0;
state <= STATE_IDLE;
end
endcase
end
end
endmodule
If you have a module pin defined as
inout wire pin
then you can access it like so
wire pin_input = pin;
assign pin = pin_oe ? pin_output : 1'bz;
this should infer a tristate buffer.
However, I would be careful when doing this, as if you infer a tristate buffer too early, it can limit what you can do with the module. For example, it would be possible to connect multiple internal I2C components together, such as allowing multiple masters inside the FPGA access to the same pins. However, tristate signals cannot be routed inside the FPGA, so if you implement the tristate inside the I2C master module, this becomes impossible. Instead, what you might consider is implementing each pin as three module pins: input, output, and output enable/tristate. This allows multiple modules to be connected with an emulated tristate bus, and allows them to share one set of tristate buffers to the actual I/O pin on the chip.
For a good example of how this works, see the comments in https://github.com/alexforencich/verilog-i2c/blob/master/rtl/i2c_master.v .

ERROR: HDLCompiler:806 ... Syntax error near "end"

I'm trying to make an I2C protocol on Verilog, and I was typing what this guy was typing (a video on YouTube that explains how to make a I2C BUS protocol)
module step1(
input wire clk,
input wire reset,
output reg i2c_sda,
output reg i2c_scl
);
//goal is to write to device addres 0x50, 0xaa
localparam STATE_IDLE = 0;
localparam STATE_START = 1;
localparam STATE_ADDR = 2;
localparam STATE_RW = 3;
localparam STATE_WACK = 4;
localparam STATE_DATA = 5;
localparam STATE_STOP = 6;
localparam STATE_WACK2 = 7;
reg [7:0] state;
reg [6:0] addr;
reg [7:0] data;
reg [7:0] count;
always #(posedge clk) begin
if (reset == 1) begin
state <= 0;
i2c_sda <= 1;
i2c_scl <= 1;
addr <= 7'h50;
count <= 8'd0;
data <= 8'haa;
end
else begin
case(state)
STATE_IDLE: begin //idle
i2c_sda <= 1;
state <= STATE_START;
end // end state idle
STATE_START: begin //start
i2c_sda <= 1;
state <= STATE_ADDR;
count <= 6;
end // end of state start
STATE_ADDR: begin // fisrt addres bit or the most significant adress bit
i2c_sda <= addr[count];
if (count == 0) state <= STATE_RW;
else count <= count - 1;
end // end of state ADDR
STATE_RW: begin // Read or Write opperation
i2c_sda <= 1;
state <= STATE_WACK;
end // end state RW
STATE_WACK: begin
state <= STATE_DATA;
count <= 7;
end // end of state WACK
STATE_DATA: begin
i2c_sda <= data[count];
if (count == 0) state <= STATE_WACK2;
else count <= count-1;
end // end of state DATA
STATE_WACK2: begin
state <= STATE_STOP;
end // end state WACK2
STATE_STOP: begin
i2c_sda <= 1;
state <= STATE_IDLE;
end // end of state STOP
end// end of case
end // end of the else
end // end of if
endmodule
But, when I try to compile, the following error pops out. I really don't understand why, because all end are correct (at least for me):
ERROR:HDLCompiler:806 - "/home/yunta23/Documentos/Digital1/VideosYou/primero/step1/step1.v" Line 97: Syntax error near "end".
A case statement requires the endcase keyword, not an end keyword. Change:
end// end of case
to:
endcase

Resources