Intel funding to develop printer for blind

subhum-banerjee-and-braille-printerA 13-year-old Indian-origin boy has received a huge investment from Intel for developing a low-cost printer for the blind, making him the youngest tech entrepreneur funded by a venture capital firm.

Shubham Banerjee, CEO of the Braille printer maker Braigo Labs, had closed an early round funding with Intel Capital, the company's venture capital arm, last month to develop a prototype of low-cost Braille printer.

But to attend the event, Banerjee had to take the day off from middle school. That’s because he’s just 13 years old — making him, quite possibly, the youngest recipient of venture capital in Silicon Valley history. (He’s definitely the youngest to receive an investment from Intel Capital.)

“I would like all of us to get together and help the visually impaired, because people have been taking advantage of them for a long time,” Banerjee said. “So I would like that to stop.”

By “taking advantage,” Banerjee is referring to the high price of Braille printers today, usually above $2,000. By contrast, Braigo Labs plans to bring its printer to market for less than $500.

Banerjee has invented a new technology that will facilitate this price cut. Patent applications are still pending, so he wouldn’t divulge any of the details. But the technology could also be used to create a dynamic Braille display — something that shows one line of text at a time by pushing small, physical pixels up and down, and which currently costs $6,500, according to Braigo advisor Henry Wedler, who is blind.

Banerjee also figures that volume production will help keep the price low. Currently, Braille printers cost so much because the demand is low, so current manufacturers need to set a high price in order to recoup their costs.

“The truth is that demand is low in the U.S.,” Banerjee told me. But, he added, if you brought the price low enough there would be huge demand outside the U.S.

Banerjee built the version version of his Lego Braille printer for a science fair. He didn’t know anything about Braille beforehand. In fact, he’d asked his parents how blind people read, he said onstage, and they were too busy to answer. “Go Google it,” he said they told him, so he did.

After learning about Braille, he came up with the idea to make a Braille printer. He showed it at his school’s science fair, then later entered it into the Synopsys Science & Technology Championship, where he won first prize, which included a big trophy and a $500 check.

After that, he started getting a lot of attention on his Facebook page. People kept asking him if they could buy one, he said, which led to the idea of creating a company.

Lego was just for the first prototype, by the way: Future versions will be made with more traditional materials.

So how did Intel come to invest in such a young inventor? His father, Niloy, works for Intel — but that’s not exactly how it happened, according to Niloy.

After working with the beta version of Intel Edison (the chip company’s tiny embeddable microprocessor) at a summer camp, Banerjee’s project came to the attention of Intel, which invited him to show off his printer at the Intel Developer Forum. After appearing at IDF, Intel Capital came calling.

Young Banerjee seems composed in front of crowds, which should serve him well. (That’s not surprising, given that Braigo’s website touts coverage on everything from BoingBoing and SlashGear to CNN and NPR.) When asked onstage, in front of 1,000 entrepreneurs, investors, and Intel employees, how he knew that the printer worked even though he doesn’t read Braille, Banerjee answered immediately, “I Googled it.” The crowd laughed.

“I’m happy that I live in Silicon Valley,” Banerjee said. “So many smart people.”

UVM - Driver

The driver is a block whose role is to interact with the DUT. The driver pulls transactions from the sequencer and sends them repetitively to the signal-level interface. This interaction will be observed and evaluated by another block, the monitor, and as a result, the driver’s functionality should only be limited to send the necessary data to the DUT.

In order to interact with our adder, the driver will execute the following operations: control the en_i signal, send the transactions pulled from the sequencer to the DUT inputs and wait for the adder to finish the operation.

So, we are going to follow these steps:

  1. Derive the driver class from the uvm_driver base class
  2. Connect the driver to the signal interface
  3. Get the item data from the sequencer, drive it to the interface and wait for the DUT execution
  4. Add UVM macros

In Code 5.1 you can find the base code pattern which is going to be used in our driver.

class simpleadder_driver extends uvm_driver#(simpleadder_transaction);
`uvm_component_utils(simpleadder_driver)   //Interface declaration
protected virtual simpleadder_if vif;   function new(string name, uvm_component parent);, parent);
endfunction: new   function void build_phase(uvm_phase phase);
void'(uvm_resource_db#(virtual simpleadder_if)::read_by_name(.scope("ifs"), .name("simpleadder_if"), .val(vif)));
endfunction: build_phase   task run_phase(uvm_phase phase);
//Our code here
endtask: run_phase
endclass: simpleadder_driver
Code 5.1 – Driver component –

The code might look complex already but what it’s represented it’s the usual code patterns from UVM. We are going to focus mainly on the run_phase() task which is where the behaviour of the driver will be stated. But before that, a simple explanation of the existing lines will be given:

  • Line 1 derives a class named simpleadder_driver from the UVM class uvm_driver. The #(simpleadder_transaction) is a SystemVerilog parameter and it represents the data type that it will be retrieved from the sequencer.

  • Line 2 refers to the UVM utilities macro explained on chapter 2.

  • Lines 7 to 9 are the class constructor.

  • Line 11 starts the build phase of the class, this phase is executed before the run phase.

  • Line 13 gets the interface from the factory database. This is the same interface we instantiated earlier in the top block.

  • Line 16 is the run phase, where the code of the driver will be executed.

Now that the driver class was explained, you might be wondering: “What exactly should I write in the run phase?”

Consulting the state machine from the chapter 1, we can see that the DUT waits for the signal en_i to be triggered before listening to the ina and inb inputs, so we need to emulate the states 0 and 1. Although we don’t intend to sample  the output of the DUT with the driver, we still need to respect it, which means, before we send another sequence, we need to wait for the DUT to output the result.

To sum up, in the run phase the following actions must be taken into account:

  1. Get a sequence item

  2. Control the en_i signal

  3. Drive the sequence item to the bus

  4. Wait a few cycles for a possible DUT response and tell the sequencer to send the next sequence item

The driver will end its operation the moment the sequencer stops sending transactions. This is done automatically by the UVM API, so the designer doesn’t need to to worry with this kind of details.

In order to write the driver, it’s easier to implement the code directly as a normal testbench and observe its behaviour through waveforms. As a result, in the next subchapter (chapter 5.1), the driver will first be implemented as a normal testbench and then we will reuse the code to implement the run phase (chapter 5.2).

Chapter 5.1 – Creating the driver as a normal testbench

For our normal testbench we will use regular Verilog code. We will need two things: generate the clock and idesginate an end for the simulation. A simulation of 30 clock cycles was defined for this testbench.

The code is represented in Code 5.2.

//Generates clock
initial begin
forever #20 clk = ! clk;
end   //Stops testbench after 30 clock cyles
always@(posedge clk)
counter_finish = counter_finish + 1;   if(counter_finish == 30) $finish;
Code 5.2 – Clock generation for the normal testbench
The behaviour of the driver follows in Code 5.3.
always@(posedge clk)
//State 0: Drives the signal en_o
en_i = 1'b1;
state_drv = 1;
end   if(counter_drv==1)
en_i = 1'b0;
end   case(state_drv)
//State 1: Transmits the two inputs ina and inb
1: begin
ina = tx_ina[1];
inb = tx_inb[1];   tx_ina = tx_ina << 1;
tx_inb = tx_inb << 1;   counter_drv = counter_drv + 1;
if(counter_drv==2) state_drv = 2;
end   //State 2: Waits for the DUT to respond
2: begin
ina = 1'b0;
inb = 1'b0;
counter_drv = counter_drv + 1;   //After the supposed response, the TB starts over
counter_drv = 0;
state_drv = 0;   //Restores the values of ina and inb
//to send again to the DUT
tx_ina <= 2'b11;
tx_inb = 2'b10;
Code 5.3 – Part of the driver

For this testbench, we are sending the values of tx_ina and  tx_inb to the DUT, they are defined in the beginning of the testbench (you can see the complete code attached to this guide).

We are sending the same value multiple times to see how the driver behaves by sending consecutive transactions.

After the execution of the Makefile, a file named simpleadder.dump will be created by VCS. To see the waveforms of the simulation, we just need to open it with DVE.

The waveform for the driver is represented on Figure 5.1.


It’s possible to see that the driver is working as expected: it drives the signal en_i on and off as well the DUT inputs ina and inb and it waits for a response of the DUT before sending the transaction again.

Chapter 5.2 – Implementing the UVM driver

After we have verified that our driver behaves as expected, we are ready to move the code into the run phase as seen in Code 5.4.

virtual task drive();
simpleadder_transaction sa_tx;
integer counter = 0, state = 0;
vif.sig_ina = 0'b0;
vif.sig_inb = 0'b0;
vif.sig_en_i = 1'b0;   forever begin
if(counter==0) begin
//Gets a transaction from the sequencer and
//stores it in the variable 'sa_tx'
end   @(posedge vif.sig_clock)
if(counter==0) begin
vif.sig_en_i = 1'b1;
state = 1;
end   if(counter==1) begin
vif.sig_en_i = 1'b0;
end   case(state)
1: begin
vif.sig_ina = sa_tx.ina[1];
vif.sig_inb = sa_tx.inb[1];   sa_tx.ina = sa_tx.ina &lt;&lt; 1;
sa_tx.inb = sa_tx.inb &lt;&lt; 1;   counter = counter + 1;
if(counter==2) state = 2;
end   2: begin
vif.sig_ina = 1'b0;
vif.sig_inb = 1'b0;
counter = counter + 1;   if(counter==6) begin
counter = 0;
state = 0;   //Informs the sequencer that the
//current operation with
//the transaction was finished
endtask: drive
Code 5.4 - Task for the run_phase()

The ports of the DUT are acessed through the virtual interface with vif.<signal> as can be seen in lines 4 to 6.

Lines 12 and 50 use a special variable from UVM, the seq_item_port to communicate with the sequencer. The driver calls the method get_next_item() to get a new transaction and once the operation is finished with the current transaction, it calls the method item_done(). If the driver calls get_next_item() but the sequencer doesn’t have any transactions left to transmit, the current task returns.

This variable is actually a UVM port and it connects to the export from the sequencer named seq_item_export. The connection is made by an upper class, in our case, the agent. Ports and exports are going to be further explained in chapter 6.0.1.

This concludes our driver, the full code for the driver can be found in the In Figure 5.2, the state of the verification environment with the driver can be seen.


Figure 5.2 – State of the verification environment with the driver

Popular Posts