Category Archives: Uncategorised

Flash memory through the ages

I was reading bunnie’s recent post on the manufacturing techniques used in USB flash-drives… bare die manipulated by hand with a stick!

Today I found an old (128MB!) SD card from my Palm Tungsten-T. Circa 2005 if I remember rightly. Very different technology, actual chips soldered down on the board. And it’s clear that the SD card form factor was very much defined by the physical size of the NAND flash chips available at the time!

The innards of an old SD card

Me: One, Tiny pieces of plastic: Nil

For want of a better place to log how to get at the dishwasher pump next time it gets stuck with a tiny piece of plastic blocking the impeller, I’m sticking it here.

In case it helps anyone else it’s a Bosch Classixx (no idea what model no, bought about 2004 IIRC). Here are the steps:

* Turn it on its side (right hand side looking at the door – the one nearest the programme dial)
* remove the bottom (remove two screws and need a flat screwdriver to prise it a bit) – it has an earth wire attached, so don’t yank it completely away
* Don’t lose the bit of polystyrene from the anti-flooding switch!
* Follow the drain hose (that goes to the u-bend under the sink) back to the pump
* Squeeze the clips and rotate the pump, it’ll come off fairly easily
* remove tiny piece of debris of some sort.
* Put it all back together again.

Is this the modern equivalent of going out hunting sabre-tooth tigers? Probably not :)

EEWeb electronic design site

I recently became aware of the EEWeb electronic design site (as one of their reps emailed me to see if I’d like my site to appear on their front page… we’ll see if my server can handle that!)

It’s sponsored by Digikey, much like RS‘s DesignSpark and Farnell‘s element14.

There’s an awful lot of content and I’ve barely scratched through a tiny bit of it – worth a trawl!

If you’re visiting from EEWeb, you might be interested in my FPGA or VHDL related writings, or my solderless Drawdio – or maybe something else!

Variables and signals in VHDL – and when variables are better

VHDL has two types of what-would-normally-be-called-variables:

  • signals, which must be used for inter-process communication, and can be used for process-local storage
  • variables which are local to a process.

(there’s also variables of a protected type which we’ll ignore for now as they’re another thing altogether)

Now one of the big differences between signals and variables is the way they are updated. When a signal is used within a process and is assigned to to change its value, the value does not update until the end of the process. For example (assume foo is “ to start with):

process
begin
  wait until rising_edge(clk);
  foo <= 1; -- an update is scheduled
  sig <= foo + 1; -- but hasn't happened yet, so sig is assigned 1 (again, only scheduled)
end process; -- at this point, foo is updated with the value 1 and sig also gets 1

Compare with the situation where foo is a variable:

process
  variable foo : integer;
begin
  wait until rising_edge(clk);
  foo := 1; -- foo gets 1 immediately
  sig <= foo + 1; -- so sig has an update to 2 scheduled
end process; -- at this point, foo is already 1 and sig gets its scheduled update to 2

This can cause some interesting effects on coding style – take for example this question on StackOverflow.

A code example is provided there which shows what has to happen due to the update semantics of signals – deeply nested ifs.

Here’s an alternative. Let’s define a procedure first of all to increment a variable and wrap around if it is greater than some maximum value. Also return a flag to inform us if the variable wrapped:

procedure inc_wrap (i : inout integer; maximum : positive; wrapped : inout boolean) is
begin
  if i = maximum then
    wrapped := true;
    i := 0;
  else
    wrapped := false;
    i := i + 1;
  end if;
end procedure;

Then our update process looks like this:

if second_enable = '1' then
  inc_wrap(s_ls_int, 9, wrapped);
  if wrapped then
    inc_wrap(s_ms_int, 5, wrapped);
  end if;
  if wrapped then
    inc_wrap(m_ls_int, 9, wrapped);
  end if;
  if wrapped then
    inc_wrap(m_ms_int, 5, wrapped);
  end if;
  if wrapped then
    if h_ms_int < 2 then -- wrap at 9 for 0-19 hour
      inc_wrap(h_ls_int, 9, wrapped);
    else -- wrap at 3 if past 20 hours
      inc_wrap(h_ls_int, 3, wrapped);
    end if;
  end if;
  if wrapped then
    inc_wrap(h_ms_int, 2, wrapped);
  end if;
end if;

All the code from this posting is at Github

libv – assert_equal, str, etc.

procedure assert_equal (
    prefix'event : string;
     got, expected : integer; 
    level : severity_level := error) is 
begin 
  assert got = expected 
    report prefix & " wrong. Got " & integer'image(got) & " expected " 
    & integer'image(expected) 
    & "(difference=" & integer'image(got-expected) &")" 
    severity level; end procedure assert_equal; 

In addition, the same API can be used for comparing more complex types (like the integer_vector type which is also part of libv):

procedure assert_equal ( prefix : string; 
                         got, expected : integer_vector; 
                         level : severity_level := error) is 
  variable g,e : integer; 
begin -- procedure assert_equal
  assert got'length = expected'length 
      report prefix & " length wrong. Got " & integer'image(got'length) 
      & " expected " & integer'image(expected'length) 
      & "(difference=" & integer'image(got'length-expected'length) &")" 
  severity level; 
  for i in 0 to got'length-1 loop 
     g := got(got'low+i); 
     e := expected(expected'low+i); 
     assert g = e 
       report prefix & " got(" & integer'image(got'low+i) & ") = " 
       & integer'image(g) & CR 
       & " expected(" & integer'image(expected'low+i) 
       & ") = " & integer'image(e) 
       severity level; 
  end loop; -- i 
end procedure assert_equal; 

or indeed a similar function for `pixel_array`:

procedure assert_equal (
prefix : string;
expected, got : pixel_array;
level : severity_level := error) is
begin -- procedure assert_equal
    assert_equal(prefix & "(width)", expected'length(1), got'length(1), level);
    assert_equal(prefix & "(height)", expected'length(2), got'length(2), level);
    for y in expected'range(2) loop
       for x in expected'range(1) loop
          assert expected(x,y)=got(x,y)
            report prefix &"(" & str(x) & "," & str(y)  &")" & 
                str(expected(x,y)) & "/=" & str(got(x,y))
            severity level;
       end loop; -- x
    end loop; -- y
end procedure assert_equal;

You’ll notice I got bored of writing integer'image and wrote a str function which takes an integer and an optional length argument and returns a string, left-padded with spaces if the length argument is longer than the integer requires:

 function str (val : integer; length : natural := 0) return string is 
   constant chars_needed : natural := num_chars(val); 
   variable s : string(1 to max(length, chars_needed)) := (others => ' '); 
 begin -- function str 
    if length = 0 then 
       return integer'image(val); 
    end if; 
    if chars_needed > length then 
       report "Can't fit " & integer'image(val) & " into " 
              & integer'image(length) & " character(s) - returning full width"
              severity warning; 
       return integer'image(val); 
    end if; 
    s(s'high-(chars_needed-1) to s'high) := integer'image(val); 
    return s; 
end function str; 

Again, this can be a standard API and we can have a str function for other types; For example, boolean:

 function str (val : boolean; length:natural range 0 to 1 := 0) return string is 
 begin -- function str 
     if length = 0 then 
       return boolean'image(val); 
     end if; 
     if length = 1 then 
       if val then 
         return "T"; 
       else 
         return "F"; 
       end if; 
     end if; 
 end function str;

Oops

It’s been very kindly pointed out to me via email (by Tricky) that I was talking complete rubbish saying that VHDL is rubbish at 2d arrays.

What I should’ve said was “VHDL is rubbish at arrays of other arrays”, which is a subtle but critical difference! Arrays of other arrays are very useful (for example in register files), and the fact that the dimensions of one of the arrays must be known at compile time can make some things tricky to impossible. For example, a generic mux with a variable number of inputs can’t easily also have a generic number of bits on each input.

This has no bearing at all on the reading, storage and writing of images! The reason I wrote what I did stems back (I think!) to the fact that I first wrote an image reading library many years ago at work and it’s worked in a similar way ever since, Now the code I published the other day is completely new, written straight out of my head, but with my “ancient” prejudices attached to it.

When Tricky wrote to me saying what’s wrong with proper 2d arrays, the light bulb pinged and I spent several hours wandering the house kicking myself! Still, it’s good to learn new things, even if you thought you already knew about them – clearly I hadn’t got them ingrained enough!

So, I’ve created a new version of the page in question, which creates a much tidier image access library.

Sorry for any confusion caused!

Reading image files with VHDL part 1


Please note that this page talks rubbish – here’s why, and here’s a better version.

If we’re going to do some image processing in VHDL, we’re going to need to be able to read images in to our simulations. VHDL’s file handling is pretty poor to say the least, so we’ll keep things simple by only handling a very simple file format – namely Portable Greymap (PGM). And for even more simplicity we’ll handle on one variant with 8-bit pixels (P2 format with Maxval<256).

Data storage

Please note that this page talks rubbish – here’s why, and here’s a better version.



VHDL’s handling of 2-D arrays is also pretty dismal – one of the dimensions has to be known at compile-time, which is not great for reading in arbitrary images. To get around this, we’ll store the pixels in a one-dimensional vector in a record along with the image height and width. This will allow us to access any pixel with an (x,y) coordinate by calculating the index:

index = y*width+x

Let’s create a package called pgm to keep all this together:

[vhdl]
package pgm is

subtype pixel is integer range 0 to 255;
type pixel_vector is array (integer range &lt;&gt;) of pixel;
type pixel_vector_ptr is access pixel_vector;
type image is record  -- storage for all the relevant info
    width, height : positive;
    pixels        : pixel_vector_ptr;
end record image;
subtype coordinate is natural;


[/vhdl]

Some points:

  • We’ve got a subtype for the raw pixel type – this enables us to change a single place if we decide to extend to (say) 16-bit pixels.
  • The record is storing an ACCESS type, like a pointer. This allows us to allocate the memory for the pixel_vector on-the-fly when the image is first read
  • The downside of this is that the image type cannot be passed to functions, so we must use procedures with inout parameters for passing images in

API

The public API for playing with the images will be simple:

  • a function to read an image from a file into an image record
  • a convenience function to read a particular pixel using (x,y) coordinates
  • a convenience function to set a particular pixel
  • a function to write an image record out to a file

[vhdl]
function pgm_read (
filename : string)
return image;
procedure pgm_write (
filename : in string;
i : inout image);

procedure get_pixel (
    i    : inout image;
    x, y : in    coordinate;
    val  : out   pixel);
procedure set_pixel (
    i    : inout image;
    x, y : in    coordinate;
    val  : in    pixel);

end package pgm;
[/vhdl]

Testing

For the input side, a simple testbench is all that is required, along with a carefully crafted PGM file for which we “know the right answers”. Following that, we can change one or more pixels with the set_pixel() interface, check that it has been done correctly, and write the new image out. Checking that final image will have to be done by hand. We could “round-trip” the image back in through our image reading function, but this may mask any errors we’ve made in the reading and writing functions which happen to cancel each other out!

[vhdl]
entity tb_pgm is
end entity tb_pgm;

use work.libv.all;
use work.pgm.all;
architecture test of tb_pgm is
begin — architecture test
test1: process is
variable i : image;
constant testdata : pixel_vector := (
000,001,002,003,005,006,007,
000,000,000,000,000,000,000,
255,255,255,255,255,255,255,
100,100,100,100,100,000,000
);
begin — process test1
i := pgm_read("test.pgm");
assert_equal("PGM Width", i.width, 8);
assert_equal("PGM Height", i.width, 4);
assert_equal("PGM data", integer_vector(i.pixels.all), integer_vector(testdata));
wait;
end process test1;

end architecture test;
[/vhdl]

The constant testdata is what we will “draw” into our image with a paint package in order to create the input image for testing.

Aside – libv

The assert_equal functions are part of my library of useful things (maybe this could be a start towards VHDL’s jQuery :) libv. Why not just use assert as is? Well, it’s useful to report all assert results in the same fashion, particularly to include the values that you expected and what you tested, along with the difference between them – often this is useful debugging information.

[vhdl]
procedure assert_equal (
prefix : string;
got, expected : integer;
level : severity_level := error) is
begin — procedure assert_equal
assert got = expected
report prefix & " wrong. Got " & integer’image(got) & " expected " & integer’image(expected) & "(difference=" & integer’image(got-expected) &")"
severity level;
end procedure assert_equal;
[/vhdl]

In addition, the same API can be used for comparing more complex types (like the integer_vector type which is also part of libv):

[vhdl]
procedure assert_equal (
prefix : string;
got, expected : integer_vector;
level : severity_level := error) is
variable g,e : integer;
begin — procedure assert_equal
assert got’length = expected’length
report prefix & " length wrong. Got " & integer’image(got’length)
& " expected " & integer’image(expected’length)
& "(difference=" & integer’image(got’length-expected’length) &")"
severity level;
for i in 0 to got’length-1 loop
g := got(got’low+i);
e := expected(expected’low+i);
assert g = e
report prefix
& " got(" & integer’image(got’low+i) & ") = " & integer’image(g) & CR
& " expected(" & integer’image(expected’low+i) & ") = " & integer’image(e)
severity level;
end loop; — i
end procedure assert_equal;
[/vhdl]

In the spirit of Test-Driven Development, all the API elements are left empty, except for the pgm_read function which has to return something. I’ve created a “constant” empty_image for it to return (except it has to be a variable as it has an access type in it).
[vhdl]
variable empty_image : image := (width => 0, height => 0, pixels => new pixel_vector(0 to -1);
[/vhdl]

Note the slightly wacky syntax to create an array of zero length: (0 to -1)

With the results:


libv.vhd:55:9:@0ms:(assertion error): PGM Width wrong. Got 0 expected 8(difference=-8)
libv.vhd:55:9:@0ms:(assertion error): PGM Height wrong. Got 0 expected 4(difference=-4)
libv.vhd:66:9:@0ms:(assertion error): PGM data length wrong. Got 0 expected 28(difference=-28)

Hurrah! It fails in the way we’d hope!

Hackadayed

Inadvertently made the front page of Hackaday with the solderless drawdio.

Which resulted in an order of magnitude more hits than normal before my server fell over with mysqld leaking its guts all over the console. The youtube video of it in operation that is also linked to from Hackaday has now had 1600+ hits!

Unfortunately, I didn’t have my VPS SSH key with me during the day, so I couldn’t fix it until the night after, so apologies to anyone who noticed the downtime.

Serves me right – I have a fairly low performance VPS hosted by the excellent people at prgmr.com, and I installed apache as the web server. I knew it was bloated and heavy, and intended to update to nginx – but until now I haven’t had the incentive :) This week’s task it to get nginx up, and maybe tune up mysqld a bit to handle things better. And then write something equally compelling to ensure it gets tested :)