Verilog Using pos/negedge as a register? - Page 1
Forum section: electronics / beginners

author: logictom
author_rank: Unknown
timestamp: April 08, 2011, 10:05:42 pm
content: I've only been learning Verilog for the last couple of weeks but I'm stumped!I'm trying to write a simple SPI master and want to include a basic register which controls which mode it is in. Idle clock polarity and edge triggering.What I want to do is something like this:reg x;if(y) x = posedge;else x = negedge;always @ (x clk)But I can't use posedge as it's a reserved keyword, there is probably a simple way to do this or a completely different way but I can't find anything on this.Any help or suggestions are always appreciated------------Oh and did I mention I hate Verilog?It's driving me mad with errors all the time, any good resources would also be a great help

author: Balaur
author_rank: Unknown
timestamp: April 08, 2011, 11:08:54 pm
content: I'm sorry, but I have some difficulty in understanding your terminology (Idle clock polarity?) and your example.You cannot assign an event (posedge or negedge) to a signal. You assign a value. If the signal was at a different value, then yes, you will have a transition.Please allow me to rephrase my way and ask you whether you want:1) a continuous (combinational) assignment such asCode:wire x;assign x = ~y;orCode:wire x;assign x = (condition) ? 0:1;orCode:reg x;always @(y) beginx = ~y;...end2) Or maybe you want a registered signal that will only change on the latching edge of the clock and will be synthesized as a flip-flop:Code:reg x;always @(posedge clk) beginx = ~y;...end(I have assumed that y is a signal, but you can use if cases as well)Cheers,Dan

author: logictom
author_rank: Unknown
timestamp: April 08, 2011, 11:49:20 pm
content: Hi Dan, thanks for replying.A little more info: I am trying to create a SPI master which in the case of a microcontroller would usually have a register for setting up the mode, clock frequency and other bits and bobs.The modes are defined with attributes: High/Low clock when idle, data transfer on rising/falling edge.ModePolarityEdge000101210311The master I am attempting to create has a register to store the mode, what I want to do is be able to read this register and create an always @ block that will be triggered on a rising or falling edge determined by the register value.The always statement will contain the logic to shift out the data on the corresponding edge.The example I gave was trying to use an if to determine the state of the register and set the edge in the always statement. Y being the register value and X just being something to hold the pos/negedge definition.Hopefully that has cleared it up?I'm new to verilog and I'm still trying to get out of the sequential flow / C programming mind set

author: joelby
author_rank: Frequent Contributor
timestamp: April 09, 2011, 04:01:25 am
content: Normally for something slow (relative to the system clock) like SPI you would use a counter to divide the clock, typically to double the SPI frequency, and then set the SPI clock high and low on alternate (positive) edges of that master clock. Don't try to mix positive and negative edges in a design unless you have a good reason to do so.

author: Balaur
author_rank: Unknown
timestamp: April 09, 2011, 07:54:42 am
content: OK, I think I have a better understanding.As suggested by joel you can go with a clock divider and a clock counter.Or, a bit closer to what you have in mind, here is an example of sampling on either edge of the clock:Code:module test(input clk,input mode,input in,output out);reg pos_sample;reg neg_sample;wire sample;always @(posedge clk) pos_sample = in;always @(negedge clk) neg_sample = in;assign sample = mode ? neg_sample : pos_sample;// Continous assignmentassign out = sample;// Registered// always @(posedge clk) out = sample;endmoduleThis code corresponds to two flip-flops, driven by either positive or negative edges of the clock and a mux to chose one of the sampled values. I would go with the registered sample output.Depending on your implementation target, the proposed idea is good (FPGA) or bad (ASIC)

author: joelby
author_rank: Frequent Contributor
timestamp: April 09, 2011, 08:21:19 am
content: I'm reluctant to ever mix posedge and negedge, so I would do something like this:input wire sample_edge;output wire spi_clock;input wire spi_miso;output reg [15:0] data_out;reg spi_clock_reg = 0;assign spi_clock = spi_clock_reg;reg state;always @(posedge spi_clock_4x)beginif (state)spi_clock_reg <= ~spi_clock_reg;else beginif (spi_clock_reg && sample_edge)begindata_out[15:1] <= data_out[14:0];data_out <= spi_mosi;end else if (~spi_clock_reg && ~sample_edge)data_out[15:1] <= data_out[14:0];data_out <= spi_mosi;endstate <= ~state;endThis way, the data is sampled 1/4 of a period after the clock transition.

author: logictom
author_rank: Unknown
timestamp: April 09, 2011, 10:16:56 pm
content: Thank you both for the help. As usual I'm juggling 101 things so keep going back and forth on this.I running into another problem, I am trying to read in some parallel data and the clock is out out serially.If I do something like the following I get an error about trying to drive from two always blocksCode:input [7:0] datain;output spi_clk;output spi_data;always @(datain)datareg = datainalways @(posedge spi_clk)beginspi_data = datareg;datareg = datareg << 1;endI'd need to add some sort of control to only read in data once it's finished sending out the last byte but that's for later once I've actually got something coming out the thing.Sorry this is probably really easy stuff but I'm racking my brains trying to figure this one out....

author: joelby
author_rank: Frequent Contributor
timestamp: April 10, 2011, 01:09:04 am
content: Unless you're doing combinatorial logic, always blocks should only be triggered by clocks, and occasionally an asynchronous reset if you have a good reason to use one. You should use write enables and busy flags to control how the module works with other parts of the system.input wire reset;input [7:0] datain;input clk;input write_enable;output reg spi_data;reg [4:0] state = 0;reg [7:0] datareg;always @(posedge clk)beginif (reset) beginstate <= 0;spi_data <= 0;end elsecase (state)0:if (write_enable) begindatareg <= datain;state <= 1'b1;end9: beginspi_data <= 0;state <= 0;enddefault: beginspi_data <= datareg;datareg[7:1] <= datareg[6:0];state <= state + 1'b1;endcaseendThis does:- After reset, go to the idle state (0).- When write_enable is asserted, save datain to datareg and proceed to transmit states (1-8).- states 1-8 are captured by the default: block. This is a simple way to use the state register as a counter. The other option would be to use a separate counter register. For eight bits, shift the MSB of data_reg into spi_data, and shift the rest up one bit.- At state 9, go back to idle state.I don't think this will work as-is, but it should give you a bit of an idea. If you were generating the clock in this state machine, you'd want to run it at double the clock rate and then only change the MOSI bit every other cycle, at your desired clock edge and polarity.

author: logictom
author_rank: Unknown
timestamp: April 17, 2011, 06:25:07 pm
content: Sorry for the late response. Thanks for the pointers joel, that was exactly the info I needed to get this off the ground, I have finished up the code and it looks good from the simulations, hopefully I'll get a chance to test it out in the next couple of weeks.