Showing posts with label c. Show all posts
Showing posts with label c. Show all posts

Monday, 4 October 2010

dsPIC33 (and PIC18) programming on my EEEPC at last

I've got an EEEPC 701, and although it is annoying in some ways (small screen, limited SSD space), it's great for portability. One of my goals when I got it was to be able to use it to help developing various microcontroller projects I've got on the go, and I especially like that it doesn't take up lots of space on my (tiny) desk when I'm hacking around. It works great with Arduino, but I prefer PICs to be honest. The issue with this is that Microchip (producers of PIC microcontrollers) want everyone to use MPLAB, which only works on Windows. And even if it worked on my Linux-based EEEPC, it probably wouldn't be too great on a 7 inch screen. Anyway, being born before 1980 (but not by much!) I still prefer command lines to IDEs anyway. My first development environment was debug.com on MS-DOS, and it's never been bettered :-)

At some point I'll get round to changing the OS (Linux Mint looks like the front runner at the mo...), but for now it's still got the Xandros stock install (though I've removed unionfs).

Rather than mess around with getting the (GCC based) Microchip tools compiled on the machine, I'm using wine - both C18 and C30 install and work without any problems.

For actually burning the image onto the controller, I use and the perfectly-working-without-lots-of-hassle pk2cmd and the brilliant PicKit2, (which was so successful Microchip went and broke it).

The following gives the commands I use to build and download the target .hex file - I've only got a single .c file (this one) for input at the moment, and haven't even got a makefile together yet. But getting this working took a couple of hours, so this is as much for reference as anything else...

#!/bin/bash

# exit on errors
set -e

C30_BASE=/home/user/.wine/drive_c/Program\ Files/Microchip/MPLAB\ C30/

echo "Building..."
wine "${C30_BASE}/bin/bin/pic30-coff-gcc.exe" -o dac_music.coff -mcpu=33fj64gp802 -Wl,--script "${C30_BASE}/support/dsPIC33F/gld/p33FJ64GP802.gld" DacMusic.c

echo "bin2hex..."
wine "${C30_BASE}/bin/bin/pic30-coff-bin2hex.exe" dac_music.coff

echo "burning..."
pk2cmd -Pdspic33fj64GP802 -Fdac_music.hex -Q -M -R -T
For reference, I've also got a similar setup for something on the PIC18. I've had this running from fairly soon after I got my EEEPC, and didn't have problems getting it up and running:
#!/bin/bash

# exit on errors
set -e

C18_BASE=/home/user/.wine/drive_c/MCC18

echo "Compiling..."
wine ${C18_BASE}/bin/mcc18-traditional.exe -ml -p=18f252 -k -Oi+ music.c

echo "Linking..."
wine ${C18_BASE}/bin/mplink.exe \\MCC18\\lkr\\18f252i.lkr /l\\MCC18\\lib /aINHX32 music.o

echo "burning..."
pk2cmd -P18f252 -Fa.hex -M -R -T

At some point I'll turn them into makefiles, but for now - I can program tiny microcontrollers with my almost-as-tiny EEEPC. Which is nice and cosy.


Image

Some time soon I'll actually write a blog post or two about the projects I'm using this with - mostly synthesizers and other various things to do with MIDI.

Monday, 30 August 2010

libftdi on Mac OS X

Update 2011/02/02: In trying to port pylibftdi to Python3, I found that the libraries which get built following the instructions below are 64-bit. All well and good, but the Python3.1 installation on Mac OS X 10.6 is 32-bit only (unlike the Python2.6 install).

While it's possible to get both 32-bit and 64-bit universal libraries, I haven't tried that yet. The solution to built 32-bit libraries was to use the following:

CFLAGS="-arch i386" ./configure && make && sudo make install

(Note I omitted libusb and sudo (for make install) in previous instructions - I've updated below). I also found I needed to do:

export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/

prior to building libusb-compat - I can't remember if this was a problem or not the first time round. Anyway, hopefully I'll have pylibftdi working with Python3 soon.
End of Update

I've not written much about my ftdi projects recently, so here's an update. I've played around with reading values from an encoder and outputting to a RGB LED with PWM, but both of these require a fairly high constant poll rate (or in the case of reading the encoder, ideally interrupt-on-change). The jitter is quite annoying, and decent PWM seems tricky, even when following FTDI's instructions (pdf link) for maxmising the buffer size. There's always going to be a gap when one buffer has finished and the next starts.

On a different note, I'm now mostly using my new Mac mini, so I've spent a few moments getting things to work there. Prerequisites:

These should be installed in the order listed; for each file, download it, untar it (tar -xf filename), then run './configure && make && sudo make install' in the new directory which tar has created.

On the Python side, there were a couple of issues when I tried to run the old code. First was that the library could not be found at all. This was due to the library extension (.so) being hardcoded. For a cross-platform solution, it seems the best way is to use the following:

from ctypes import *
from ctypes.util import find_library

dll = CDLL(find_library('ftdi'))
Rather than specifying 'libftdi.so', we have stripped off the 'lib' prefix and the .so extension. The simple 'ftdi' string would be used if we were linking this library with gcc using the -l flag. Try 'gcc -lftdi' and it should report only that it can't find _main, not that the library is missing (try gcc -lmadeupname and it should complain about being unable to find 'madeupname')

Once this was done, the program would some times run (especially under pdb, which lead me up the garden path of thinking it was a timing issue...), but other times would cause a segfault. This was tracked down to another hard-coded value - the size of the context structure. The following will report the size of the ftdi_context structure:

echo -e '#include \nint main(){return sizeof(struct ftdi_context);}' | gcc -xc - && (./a.out; echo $?)
This is somewhat fragile, as it will fail if the structure ever gets larger than 255 bytes, but this seems unlikely for the time being. On this Mac this gives 112 bytes; on my Linux boxes it gives 84 - though they are running on the previous (0.17) version of libftdi. There is also the issue that the Mac library is x86_64 (i.e. 64-bit), while the Linux libraries are 32-bit.

One solution, though not exactly a purist's, is to allocate far more memory than will be needed. It won't slow anything down, as only a pointer to the start of the block is passed around, and probably won't make a difference to the memory consumption as applications will always use whole numbers of pages (4KB minimum) anyway. So for now, an allocation of 1KB seems a good solution.

The result of this is that the changes needed to the earlier code for compatibility with both Mac OS X and Linux are as follows:

...

from ctypes.util import find_library

def ftdi_start():
    global ctx, fdll  # frown... :P
    fdll = CDLL(find_library('libftdi'))
    # size of ftdi_context varies
    # seen 112 (x86_64, v0.18). 84 (i386, v0.17)
    # over-allocate to 1KB.
    ctx = create_string_buffer(1024)
    fdll.ftdi_init(byref(ctx))
    fdll.ftdi_usb_open(byref(ctx), 0x0403, 0x6001)
    fdll.ftdi_set_bitmode(byref(ctx), 0xFF, 0x01)

...

Me loves os.name == 'posix' :-)

Thursday, 27 May 2010

Let there be LEDs

"In the beginning, [...] God said 'let there be light'".

Some time later, Man discovered Gallium Arsenide, and eye-piercing LEDs have blighted us ever-since.  (Although they used to be quite dim, actually).  Nevertheless, the 'hello world' of the embedded world is to make an LED flash.

In part 1 I 'covered' installation and test of the libftdi module, but the program didn't actually do anything.  The UM232R module is primarily a UART module (unlike the DLP USB245M, which is a FIFO), but as with most recent FTDI devices it supports a 'BitBang' mode.  BitBang is embedded jargon for running a protocol at the digital bit level, specifying in firmware at what point each of the (potentially many) IO lines goes high or low.

To put these devices in to this mode, an API call is needed to the FTDI driver to establish this mode.  The ftdi_set_bitmode function takes three parameters; the FTDI control context (by reference), a direction bitmap, and a mode indicator (which should be 1 for async bitbang mode).  The interesting is the direction bitmap.  For each of the 8 IO lines, the corresponding bit in this mask can be a '1' to indicate an output, or a '0' for an input.  I'm starting with output, so...

if ((ret = ftdi_set_bitmode(&ftdic, 0xFF, 0x01)) < 0) {
        fprintf(stderr, "unable to set bitmode\n");
        return EXIT_FAILURE;
    }
(this fits into the 'DO STUFF HERE' part of the code from last time)

Once this is done, we can start writing things out to the data port.
unsigned char x = 0;
    while (1) {
        ftdi_write_data(&ftdic, &x, 1);
        x ^= 0xFF;      /* toggle all lines */
        usleep(100000)  /* pause for 100ms  */
    }

This is hackish - it never exits for a start - but it should enable an LED to flash!

ImageIn terms of wiring things up, the 'GND' pin needs to go to the shorter leg of the LED (the cathode), and a data line (it doesn't matter which in this example, use DB0 to be safe) goes to the longer lead (anode).  A 1K resistor needs to be in either line to limit the current and prevent burning out the LED. As supplied, the jumpers on the UM232R/UM245R module configure it to be self powered. Anyway, it should look something like this, and the LED should be flashing at approx 5Hz.

To do anything more interesting, let's move to Python.  This is where the fun begins - with ctypes. I remember the first time I used ctypes, using puts from the C standard library on a Solaris machine, and the fact that it just worked. Occasionally there is a need to write the equivalent of a function prototype, but most of the time things are incredibly easy.

First up: loading the shared library. Lets guess its name - libftdi.so?

[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-20)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> from ctypes import *
>>>
>>> fdll = CDLL('libftdi.so')
>>>
>>> fdll
<CDLL 'libftdi.so', handle 81da028 at b7cfd4ac>
>>>

So far so good :) Next thing is this ftdi_context struct which is referenced by each function in the C code. It starts as an unpopulated structure, and presumably the first functions (init and usb_open) set it up as required.  While the D2XX interface just gives an integer handle, in libftdi we have to pass pointers to this structure around.  So, how do we define this in ctypes?
First we need its size:

#include "ftdi.h"
#include "stdio.h"
int main()
{
    printf ("%d\n", sizeof(struct ftdi_context));
}

Now compile and run...

/home/user/ftdi> gcc get_size.c
/home/user/ftdi> ./a.out
84

So, we need 84 bytes of storage for this context. ctypes will do that for us:

>>> ftdic = create_string_buffer(84) 

Done that. Now we can rattle it off: only two other things: first, where in C you give &var to give the address of a variable (e.g. as a parameter to a function taking *var), in Python with ctypes, it's byref(var). Second, to create a something which has existence in the C world, (e.g. so can have its address taken), there are a whole bunch of c_XXX functions - we'll use c_byte, which is equivalent to an unsigned char.

from ctypes import *

fdll = CDLL('libftdi.so')

ftdic = create_string_buffer(84)

fdll.ftdi_init(byref(ftdic))

fdll.ftdi_usb_open(byref(ftdic), 0x0403, 0x6001)

fdll.ftdi_set_bitmode(byref(ftdic), 0xFF, 0x01)

import time
x = c_byte(0)
try:
    while True:
        fdll.ftdi_write_data(byref(ftdic), byref(x), 1)
        time.sleep(0.1)
        x.value ^= 0xFF # toggle all bits
except KeyboardInterrupt:
    pass

fdll.ftdi_usb_close(byref(ftdic))

fdll.ftdi_deinit(byref(ftdic))

And we're done! It's surprising how easy it is to translate basic C code using libraries into Python using ctypes - normally it just works.

Next time we'll look at interfacing to an LCD module...

Tuesday, 18 May 2010

The outside world...

I'm going to do a series of blog posts on using FTDI devices to access the outside world. There are probably a dozen other similar series out there, so I hope I can introduce enough novelty to make it interesting

I've been interested in low-level programming for as long as I've been programming (anyone else remember this book? - yes, a "children's" book on Machine Code...)

In terms of 'physical computing', things like Arduino are really taking off at the moment, but I'm going to take a step back to the simplicity of simple digital IO based on the BitBang mode of FTDI's latest devices.  There are two reasons for this: firstly it came seem laborious writing two sets of software (for both the host computer and the target micro-controller), and secondly that even if the eventual application is going to be a standalone micro based system, it is still generally quicker to prototype things using only the host computer, avoiding the cross-compile and firmware upload cycle.
Image
Hardware-wise, I'm using a FTDI UM232R (Farnell link) device.  (I've also used one of these, and this either will be usable) This is a DIL module which plugs nicely into a breadboard which can be used to interface with stuff.  If you want to follow along, get a breadboard to plug it into, some LEDs, 1Kohm resistors, and some connecting wire (I like these, but they are waaay over priced).  In a couple of posts I'll be using one of these (N26AZ), too...

On the software side, I'm using Linux on a EEEPC 701 (stock Xandros) with the libftdi drivers, compiled from source found here.  The FTDI supplied drivers are similar and might be a better choice on Windows (not sure if libftdi works on Windows), but some of the function names and interfaces differ somewhat.

First step is getting the simple.c program compiled and working.  The program outline - slightly edited for length - looks something like this.

/* see http://www.intra2net.com/en/developer/libftdi/documentation/ */ 
#include "stdio.h"
#include "ftdi.h"

int main(void)
{
    int ret;
    struct ftdi_context ftdic;
    if (ftdi_init(&ftdic) < 0) {
        return EXIT_FAILURE;
    }

    if ((ret = ftdi_usb_open(&ftdic, 0x0403, 0x6001)) < 0) {
        return EXIT_FAILURE;
    }

    /* DO STUFF HERE */

    if ((ret = ftdi_usb_close(&ftdic)) < 0) {
        return EXIT_FAILURE;
    }

    ftdi_deinit(&ftdic);

    return EXIT_SUCCESS;
}
Compiling this (gcc -o simple simple.c -lftdi) and running the resulting executable should not cause any errors, and should return a successful error code if a FTDI device is attached.

This post is getting long enough for now, so I'll leave it at that. Next time will be configuring bitbang mode, where we can use the device as a configurable 8-bit IO port, blinking lights, and the wonders of Python's ctypes module...