Page 1 of 2

Microblaze on Mojo?

Posted: November 7th, 2013, 10:21 am
by maurice
After having some success getting the Picoblaze core running on Mojo, I decided to try for the next level - Microblaze. That CPU is much more powerful, has gnu compilers, etc and should be a good base for many experiments.

I found that Jim Duckworth's step by step guide http://ece.wpi.edu/~rjduck/Microblaze%2 ... l%20v2.pdf was really useful. Using it I was able to instantiate the Microblaze core, compile a C program and create an updated bit file. And this is just using the free Xilinx tools.

Nothing is easy...its not working yet. So I have a couple of questions for the experts on the forum:

1) The Microblaze core can include a UART. I included it and set it to 115200 baud and connected it directly to the avr rx/tx pins at the top level, dropping the uart from the avr interface. However I'm not clear how the AVR determines the baud rate. With putty I can see something come from the avr serial port when I hit the reset button but its garbage. I guess I can use the avr interface uart but it seems a bit wasteful to use it when there is a perfectly good one in the Microblaze.

2) The Mojo loader looks for and loads a .bin file. I think the scripts that update the rom memory with your code work on the .bit file. I rebuilt the C app, ran the scripts and it updated the .bit file, leaving the .bin file unchanged.

3) Has anyone else tried Microblaze on Mojo?

Re: Microblaze on Mojo?

Posted: November 10th, 2013, 5:30 pm
by maurice
I made a little progress on this experiment. I found that the promgen tool can convert a .bit file to a .bin file for the Mojo loader.

My command (in the TCL console) was:
promgen -u 0 mojo_top.bit -b -p bin -w

I added some code to write to the GPIO output and it works, so my Microblaze program is loading and running! But I still cant figure out the baud rate problem. I just get garbage out of the usb com port when Microblaze writes strings.

How does the Avr determine the baud rate of the serial data from the FPGA?

Thanks for any advice!

Re: Microblaze on Mojo?

Posted: November 11th, 2013, 12:01 pm
by maurice
It seems to me that the avr baud rate is fixed at 500000 bd. And the Microblaze standard uart doesnt work at that non standard rate with a 50MHz clock. I tried instantiating a Microblaze uart with programmable baud rate and trying different rates near 500K but I'm still getting garbage characters out. So I'll probably have to use GPIO or the IO bus to communicate. Its a pity, because the MB uart is tied into the C libraries which would be very convenient.

But, in short, you CAN use the Microblaze core on Mojo. And you can program it in C using the SDK and create a bitstream that can be loaded with the Mojo loader if you follow my notes.

Re: Microblaze on Mojo?

Posted: November 12th, 2013, 5:58 pm
by embmicro
Hello Maurice,

I've recently added a MicroBlaze core to one of our demo projects and I can confirm the trouble with the baud rates. I think the most elegant solution would be to internally read the serial port of the CPU and pass it's data along to the avr_interface module. If I end up doing this I'll share my adapter module.

You could also modify the AVR firmware since it is open source, but that is a bit more work.

Justin

Re: Microblaze on Mojo?

Posted: November 12th, 2013, 6:44 pm
by maurice
Hi Justin. I'm glad that you are adding a tutorial on adding the Microblaze core. That will make the Mojo board a lot more useful for large scale experimenting.

To get around the avr baud rate problem I connected the Microblaze uart directly to the external pins. Then connected a bluetooth serial port to them so I could connect from my desktop using putty. That worked great, so everything is basically working as expected.

If I have time I might try modifying the avr firmware to put the uart at 115200 bd instead of 500K.

The next thing I want to try is adding some custom peripherals using the Microblaze IO bus. It doesnt look too hard but I'm sure it will be a challenge.

Re: Microblaze on Mojo?

Posted: November 14th, 2013, 3:21 pm
by maurice
I took your advice Justin and added a "serial converter" that took the data from the MB and sent it on to the avr interface. It works. I simpy instantiated another serial rx module and added a little state machine to transfer the data when its ready. Now the standard MB serial output (at 9600 bd at the moment) goes directly to the avr and then to the usb interface. That makes debugging easy.

I also tried making a soft uart in MB code to send data at 500KB on a GPIO output that was connected to the avr input. It turned out to be more difficult than I imagined. I couldnt get the bit toggle to be fast enough to reliably send bits at exactly the right time. The functions to read and write the GPIO include some checking code which slows them down considerably. I made a "fast gpio write" function that avoid the checking that can toggle a GPIO bit in about 1.5us, but tuning the high and low bit times with "nop" instructions to exactly 2us was frustrating. I would have to write the function in MB assembler to get the timing perfect. So, I punted and added a "hardware" serial converter block at the top level.

I'm happy to share anything I've done.

Re: Microblaze on Mojo?

Posted: November 15th, 2013, 9:26 am
by yabapolido
Hi maurice,
Could you please post the source of that "serial converter" ?
I'm also trying to connect one module to AVR and experiencing some dificulties.
Thank you.

Re: Microblaze on Mojo?

Posted: November 15th, 2013, 11:39 am
by maurice
Sure. Here is my top level module, which includes the tiny serial baud rate converter state machine. I'm just using the existing avr serial interface module again but changing the baud rate. Excuse my messy code. It contains remnants of several experiments.

Code: Select all

module mojo_top(
    input clk,
    input rst_n,
    input cclk,
    output[7:0]led,
    output spi_miso,
    input spi_ss,
    input spi_mosi,
    input spi_sck,
    output [3:0] spi_channel,
    input avr_tx,
    output avr_rx,
	 output bt_rx, // bluetooth modem
	 input bt_tx,
    input avr_rx_busy,
	 // Display
	 output pwm_out // lcd backlight
    );

wire rst = ~rst_n;
wire lcd_reset = rst;

assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Serial port on avr interface
reg [7:0] tx_data;
reg new_tx_data;
wire tx_busy;
wire [7:0] rx_data;
wire new_rx_data;

// Mojo board leds
//reg [7:0] led = 8'b10101010;

// Mojo fpga-avr interface
avr_interface avr_interface (
    .clk(clk),
    .rst(rst),
    .cclk(cclk),
    .spi_miso(spi_miso),
    .spi_mosi(spi_mosi),
    .spi_sck(spi_sck),
    .spi_ss(spi_ss),
    .spi_channel(spi_channel),
    .tx(avr_rx), // FPGA tx goes to AVR rx
    .rx(avr_tx),
    .channel(4'd15), // invalid channel disables the ADC
    .new_sample(),
    .sample(),
    .sample_channel(),
    .tx_data(tx_data),
    .new_tx_data(new_tx_data),
    .tx_busy(tx_busy),
    .tx_block(avr_rx_busy),
    .rx_data(rx_data),
    .new_rx_data(new_rx_data)
);

wire [7:0] GPO1;
wire [7:0] GPO2;
wire [7:0] GPI1;

assign pwm_out = new_mb_data; // from blaze
assign bt_rx = mb_tx;
 
//assign GPI1[0] = avr_rx_busy;

wire new_mb_data;
wire [7:0] mb_data;

// Intermediate serial converter - reads from MB at 9600, writes to avr interface
serial_rx  #(.CLK_PER_BIT(5208), .CTR_SIZE(16)) mb_rx (
	.clk(clk),
	.rst(rst),
	.rx(mb_tx),
	.data(mb_data),
	.new_data(new_mb_data)
);

localparam SC_IDLE = 2'b00, SC_READ = 2'b01, SC_WRITE = 2'b10;

reg [1:0] sc_state = SC_IDLE;

always @(posedge clk) begin
	if (rst || avr_rx_busy || tx_busy) begin
		sc_state <= SC_IDLE;
		new_tx_data <= 0;
		end else begin
		case (sc_state)
		
		SC_IDLE: begin
		if (new_mb_data) begin
			sc_state <= SC_READ;
			end
		end
		
		SC_READ: begin
			tx_data = mb_data;
			sc_state <= SC_WRITE;
		end
		
		SC_WRITE: begin
			new_tx_data <= 1;
			sc_state <= SC_IDLE;
			end
		endcase
		end // else
	
end


// Instantiate Microblaze CPU - 2 GPIO, PIT, IOBUS
microblaze_cpu mbz_0 (
  .Clk(clk), // input Clk
  .Reset(rst), // input Reset
  // Peripheral IO bus
  .IO_Addr_Strobe(IO_Addr_Strobe), // output IO_Addr_Strobe
  .IO_Read_Strobe(IO_Read_Strobe), // output IO_Read_Strobe
  .IO_Write_Strobe(IO_Write_Strobe), // output IO_Write_Strobe
  .IO_Address(IO_Address), // output [31 : 0] IO_Address
  .IO_Byte_Enable(IO_Byte_Enable), // output [3 : 0] IO_Byte_Enable
  .IO_Write_Data(IO_Write_Data), // output [31 : 0] IO_Write_Data
  .IO_Read_Data(IO_Read_Data), // input [31 : 0] IO_Read_Data
  .IO_Ready(IO_Ready), // input IO_Ready
// 
  .UART_Rx(bt_tx), // input UART_Rx
  .UART_Tx(mb_tx), // output UART_Tx
  
  .PIT1_Toggle(PIT1_Toggle), // output PIT1_Toggle
  .GPO1(led), // output [7 : 0] GPO1
  .GPO2(GPO2),
  .GPI1(GPI1), // input [7 : 0] GPI1
  .GPI2(GPI2),
  .GPI1_Interrupt(GPI1_Interrupt), // output GPI1_Interrupt
  .GPI2_Interrupt(GPI2_Interrupt)
);


endmodule

Re: Microblaze on Mojo?

Posted: November 15th, 2013, 1:39 pm
by yabapolido
Thanks! I'll try it tonight :)

Re: Microblaze on Mojo?

Posted: November 17th, 2013, 7:19 pm
by maurice
I got it working in both directions and made a new module bitrate_converter to save cluttering up the top level module. The code for it is below. Its tricky to keep the inputs and outputs sorted because there are so many receivers and transmitters.

Code: Select all

module bitrate_converter(
    input clk,
    input rst,
    input rx,  // from mb_tx
    output [7:0] rx_data, // to avr
    output rx_new_data, // to avr
    input rx_block, // avr serial interface is busy
	 output tx, // to mb_rx
    input tx_new_data, // from avr
    input [7:0] tx_data // from avr side
    );
	 
wire from_mb_new_data;	 
wire [7:0] from_mb_data;
reg rx_new_data;
reg [7:0] rx_data;
wire mb_tx_busy;
reg [7:0] mb_tx_data;
reg new_mb_tx_data;
	 
// reads from MB at 9600, writes to avr interface
serial_rx  #(.CLK_PER_BIT(5208), .CTR_SIZE(16)) sc_rx (
	.clk(clk),
	.rst(rst),
	.rx(rx),
	.data(from_mb_data),
	.new_data(from_mb_new_data)
);

// reads from avr serial interface and sends it to the MB at 9600 bd
serial_tx #(.CLK_PER_BIT(5208), .CTR_SIZE(16)) sc_tx (
	.clk(clk),
	.rst(rst),
	.tx(tx),			// Serial transmitter -> mb_rx input
	.block(1'b0), // never
	.busy(mb_tx_busy), // busy sending a char to mb
	.data(mb_tx_data),	// data to send (came from avr)
	.new_data(new_mb_tx_data)	 // start sending to mb
);



// Serial mb->avr converter state machine

localparam SC_IDLE = 2'b00, SC_READ = 2'b01, SC_WRITE = 2'b10;

reg [1:0] scr_state = SC_IDLE;
reg [1:0] sct_state = SC_IDLE;

always @(posedge clk) begin
	if (rst || rx_block) begin
		scr_state <= SC_IDLE;
		rx_new_data <= 0;
		end else 
		case (scr_state)
		
		SC_IDLE: begin
		if (from_mb_new_data) begin
			scr_state <= SC_READ;
			end
		end
		
		SC_READ: begin
			rx_data = from_mb_data;
			scr_state <= SC_WRITE;
		end
		
		SC_WRITE: begin
			rx_new_data <= 1;
			scr_state <= SC_IDLE;
			end
		endcase
end // scr state mc

// serial avr to mb uart state machine
// really needs buffering because there is no blocking of fast data from avr

always @(posedge clk) begin
	if (rst) begin 
		sct_state <= SC_IDLE;
		new_mb_tx_data <= 0;
		end else 
		case (sct_state)
		
		SC_IDLE: begin
		new_mb_tx_data <= 0;
		if (tx_new_data & ~mb_tx_busy) begin // new data from avr arrived
			sct_state <= SC_READ;
			end
		end
		
		SC_READ: begin
			mb_tx_data = tx_data;
			sct_state <= SC_WRITE;
		end
		
		SC_WRITE: begin
			new_mb_tx_data <= 1; // send it to mb
			sct_state <= SC_IDLE;
			end
		endcase
end // scr state mc

endmodule
And the instantiation at the top level looks like this:

Code: Select all

bitrate_converter  br_conv(
    .clk(clk),
    .rst(rst),
    .rx(mb_tx),  // from mb_tx
    .rx_data(tx_data), // to avr
    .rx_new_data(new_tx_data),
    .rx_block(tx_busy),
	 .tx(mb_rx), // to mb_rx
    .tx_new_data(new_rx_data), // from avr
    .tx_data(rx_data) // from avr side
);
Hope this is useful to someone.

Also in your C code you should use xil_printf() ,print() ,inbyte() and outbyte() if possible to keep the memory requirements down. If you use the standard C stdio routines you'll need to allocate lots more memory. My test program is currently around 12kb.