Using the SPI feature

by dion.swamp.dk on Sat Sep 01, 2007 5:12 pm

Every single announcement about USBtinyISP mentions that it is an " AVR programmer and SPI interface", that made me think that it would be possible to use SPI as a sort of debug output port while the target code runs, but I can't find any software that actually uses that feature and no documentation either.

Any idea where I might start to look for clues as to how to use SPI?
dion.swamp.dk
 
Posts: 9
Joined: Sat Sep 01, 2007 4:53 pm
Location: Denmark

by adafruit on Sat Sep 01, 2007 6:32 pm

There is some example code linked at the bottom of this page
http://www.ladyada.net/make/usbtinyisp/use.html
User avatar
adafruit
 
Posts: 11666
Joined: Thu Apr 06, 2006 3:21 pm
Location: nyc

by dion.swamp.dk on Sun Sep 02, 2007 1:02 am

I'm sorry, I should have said that I looked at the avrdude and example driver sources but didn't find anything.

The exampledriver is missing usbdriver.h:
[code]> make
gcc -c -g -I. usbdriver.cpp
usbdriver.cpp:9:23: error: usbdriver.h: No such file or directory
usbdriver.cpp: In function ‘usb_dev_handle* acquireTinyISP()’:
usbdriver.cpp:42: error: ‘TINYISP_VENDORID’ was not declared in this scope
usbdriver.cpp:43: error: ‘TINYISP_PRODUCTID’ was not declared in this scope
usbdriver.cpp: In function ‘void dataToDisplay(std::string)’:
usbdriver.cpp:68: error: ‘USBTINY_CLR’ was not declared in this scope
usbdriver.cpp:73: error: ‘USBTINY_SPI1’ was not declared in this scope
usbdriver.cpp:75: error: ‘USBTINY_SET’ was not declared in this scope
usbdriver.cpp: In function ‘int main(int, char**)’:
usbdriver.cpp:91: error: ‘USBTINY_POWERUP’ was not declared in this scope
usbdriver.cpp:91: error: ‘RESET_LOW’ was not declared in this scope
usbdriver.cpp:93: error: ‘RESET_HIGH’ was not declared in this scope
usbdriver.cpp:100: error: ‘USBTINY_DDRWRITE’ was not declared in this scope
usbdriver.cpp:102: error: ‘USBTINY_SET’ was not declared in this scope
usbdriver.cpp:105: error: ‘USBTINY_POWERDOWN’ was not declared in this scope
make: *** [usbdriver.o] Error 1
[/code]

it looks as though some of the constants could be lifted from usbtiny.c in avrdude, but some cannot, like USBTINY_SPI1 and USBTINY_DDRWRITE.


Looking further I see that spi/main.c in the firmware sources contain the command constants, including USBTINY_SPI1 and USBTINY_DDRWRITE, I guess I should have looked more closely at the firmware than I did.


I'm still not entirely clear on how to read and write SPI, so if there is anyone who has example code to share then please let me know.
dion.swamp.dk
 
Posts: 9
Joined: Sat Sep 01, 2007 4:53 pm
Location: Denmark

updates

by jgrauman on Fri Jan 04, 2008 12:50 am

Any updates on this? I'm looking for usbdriver.h as well. Thanks.
jgrauman
 
Posts: 10
Joined: Fri Jan 04, 2008 12:45 am

Re: updates

by rb76543 on Fri Jan 04, 2008 7:06 am

jgrauman wrote:Any updates on this? I'm looking for usbdriver.h as well. Thanks.


first of all, note that i am a horrible programmer, and have no clue how things should be done. i play around until my stuff works. so, the following works for me, but it probably has some pretty stupid stuff in it...

usbdriver.h is in avrdude - see the links here, plus what i did to get avrdude to compile. (EDIT - this is incorrect. usbdriver.h is NOT in the avrdude package i used. see later post in this thread for more info)


http://www.ladyada.net/forums/viewtopic.php?t=4665

if you can get avrdude to compile and run, you can then modify it to do anything you like. to send one byte to your avr, you can do this:

int timeout;

unsigned char outbyte;
unsigned char result;

timeout = USB_TIMEOUT + (1 * sck_period) / 1000; // i have no idea
// as to whether this is stupid. it works for me.

outbyte = 0x31; we will send this to the avr. 0x31 is a value that your
avr will get through spi. you might already know that spi responds with the value that is already in spdr. so, you need to send another byte to actually get a response to this byte. did that make sense? if not, check out the atmel docs for your avr




bytes = usb_control_msg(usb_handle,
USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
USBTINY_SPI1,
outbyte,1,
&result, 1, // the response will be in result
timeout);

that is how i send one byte, but if you want to get lots of data from your avr, it is faster to use the following, which sends and receives 4 bytes with one usb transaction:

int w1,w2; // we need 16 bits. this works for me, lol.
unsigned char res[4];

if your avr is in a loop, and knows what it is expected to send, w1 and w2 can be 0, or anything. but, if you want them to convey information, load them like this:

w1 = something + (something_else << 8);
// this is supposed to say 'left shift by 8 bits, but i'm seeing stupid emoticons in the preview.
w2 = more_stuff + (more_stuff2 << 8);

i used the silly names because i don't know the order in which they actually are sent, since all of my routines send one command byte to my avr using my first example above, then dummy bytes to get the data back using this method.


usb_in( USBTINY_SPI,w2, w1, res, sizeof(res), timeout);

the first response byte is in res[0], 2nd in res[1], etc.

you might have noticed that some of the code controls the SS pin on the avr, which is recommended by atmel as a way to keep data synchronized. it isn't needed for programming, because the avr is reset. to control SS, you need to pick an unused pin on the 2313, then use something like this:


int b0,b1,b2,b3,b4,b5,b6,b7;
b0 = 0x01; // green led
b1 = 0x02; // output - i use this for SS
b2 = 0;
//b2 = 0 & 0x04; // input
b3 = 0x08; // output - hmm, this looks wrong. this pin isnt used,
so it probably should be 0, to keep it as an input. like i said, i'm a pretty
horrible programmer.
b4 = 0x10; // reset - output
b5 = 0x20; // mosi - output
b6 = 0;
//b6 = 0 & 0x40; // miso - input
b7 = 0x80; // sck - output

data_2 = b0 + b1 + b2 + b3 + b4 + b5 + b6 + b7;// 1011 1011 BB
usb_control(USBTINY_DDRWRITE, data_2, 0);

now that pin b1 is configured as an output, if it is connected to SS on your avr, pull it low to start an spi transfer, of one or more bytes:

usb_control(USBTINY_SET, 1, 0); // the '1' refers to pin 1 on port b

then raise it when you're done. on a robust system you can leave it low all the time, but if you raise and lower it periodically you ensure that the avr is re-synced.

to raise it:

usb_control(USBTINY_CLR, 1,0);

i have to go to work now, so this is pretty rough.

later,

rod
Last edited by rb76543 on Sun Mar 30, 2008 3:29 am, edited 1 time in total.
yay for open source
rb76543
 
Posts: 27
Joined: Sat Dec 15, 2007 6:52 pm

by CNLohr on Sun Mar 30, 2008 1:55 am

usbdriver.h is not in avrdude. Or, at least in avrdude-5.5.tar.gz.

I am getting the same error everyone else is getting.

Code: Select all | TOGGLE FULL SIZE
gcc -c -g -I.   usbdriver.cpp
usbdriver.cpp:9:23: error: usbdriver.h: No such file or directory
usbdriver.cpp: In function 'usb_dev_handle* acquireTinyISP()':
usbdriver.cpp:42: error: 'TINYISP_VENDORID' was not declared in this scope
usbdriver.cpp:43: error: 'TINYISP_PRODUCTID' was not declared in this scope
usbdriver.cpp: In function 'void dataToDisplay(std::string)':
usbdriver.cpp:68: error: 'USBTINY_CLR' was not declared in this scope
usbdriver.cpp:73: error: 'USBTINY_SPI1' was not declared in this scope
usbdriver.cpp:75: error: 'USBTINY_SET' was not declared in this scope
usbdriver.cpp: In function 'int main(int, char**)':
usbdriver.cpp:91: error: 'USBTINY_POWERUP' was not declared in this scope
usbdriver.cpp:91: error: 'RESET_LOW' was not declared in this scope
usbdriver.cpp:93: error: 'RESET_HIGH' was not declared in this scope
usbdriver.cpp:100: error: 'USBTINY_DDRWRITE' was not declared in this scope
usbdriver.cpp:102: error: 'USBTINY_SET' was not declared in this scope
usbdriver.cpp:105: error: 'USBTINY_POWERDOWN' was not declared in this scope


'USBTINY_CLR' is covered in usbtiny.h that is provided with AVRdude, but 'TINYISP_VENDORID' is not anywhere in any of the AVRDude source code.

I think the author forgot o include the "usbdriver.h" header for the "usbdriver.cpp" source.

It would be great if they actually included it.
CNLohr
 
Posts: 2
Joined: Sun Mar 30, 2008 1:36 am

by rb76543 on Sun Mar 30, 2008 3:37 am

CNLohr wrote:usbdriver.h is not in avrdude. Or, at least in avrdude-5.5.tar.gz.

I am getting the same error everyone else is getting.

[code]gcc -c -g -I. usbdriver.cpp
usbdriver.cpp:9:23: error: usbdriver.h: No such file or directory
usbdriver.cpp: In function 'usb_dev_handle* acquireTinyISP()':
usbdriver.cpp:42: error: 'TINYISP_VENDORID' was not declared in this scope
usbdriver.cpp:43: error: 'TINYISP_PRODUCTID' was not declared in this scope

[...]

'USBTINY_CLR' is covered in usbtiny.h that is provided with AVRdude, but 'TINYISP_VENDORID' is not anywhere in any of the AVRDude source code.

I think the author forgot o include the "usbdriver.h" header for the "usbdriver.cpp" source.

It would be great if they actually included it.


i was wrong. sorry about that. i'm using the plain C code, so i guess that's why it compiled. here is part of the usbtiny.h file that covers these things, with different names:


// these are specifically assigned to USBtiny,
// if you need your own VID and PIDs you can get them for cheap from
// www.mecanique.co.uk so please don't reuse these. Thanks!
#define USBTINY_VENDOR 0x1781
#define USBTINY_PRODUCT 0x0C9F
yay for open source
rb76543
 
Posts: 27
Joined: Sat Dec 15, 2007 6:52 pm

Re: Using the SPI feature

by sgoadhouse on Tue Jul 28, 2009 8:34 pm

It seems obvious to me now that the code referenced at the bottom of http://www.ladyada.net/make/usbtinyisp/use.html does not really work. If the zip file had the missing usbdriver.h header file and you used what must be slightly modified hardware (/SS [or RESET] is expected at PB1 in the code instead of where USBtinyISP has it at PB4), then it may work. I decided to dust off my internal programming cobwebs and give it a go at making it work. I used code from avrdude and suggestions in this forum and got it working. Seeing how there are lots of questions in the forum pointing out that the code referenced above does not compile, I wanted to share with you all what I was able to get to work.

This code reads a Microchip SPI EEPROM. You give it the byte offset desired as the first argument on the command line and it reads and returns its byte value. For other SPI EEPROMs, you'll most likely need to change EEPROM_READ_CMD in usbdriver.cpp. Also, you'll need to hook up the RESET line to the chip's /CS or /SS chip select line as well as connecting the SCLK, MISO and MOSI lines as expected.

The makefile has some options so that you can compile on OSX. If you don't have OSX, you'll need to comment out the CFLAGS and LIB variable and uncomment the original ones (see the comments in the makefile). I do not know if the original CFLAGS and LIB values work properly on other systems so you may need to point to where your libusb include files and libraries are. (NOTE: must have libusb (http://libusb.wiki.sourceforge.net/) installed for this code to work).

Here's the code:
USBtinyISP_SPI.zip
http://www.ladyada.net/make/usbtinyisp/use.html modified to work properly. If not running on OSX, need to modify makefile.
(27.28 KiB) Downloaded 837 times
sgoadhouse
 
Posts: 6
Joined: Mon Jul 13, 2009 5:59 pm

Re: Using the SPI feature

by adafruit on Tue Jul 28, 2009 9:13 pm

yay! thanks! i lost my dev environment, i thought usbdriver.h came with libusb, no?
its been years :cry:
User avatar
adafruit
 
Posts: 11666
Joined: Thu Apr 06, 2006 3:21 pm
Location: nyc

Re: Using the SPI feature

by sgoadhouse on Tue Aug 25, 2009 7:14 pm

Sorry for the slow response ...

I could not find usbdriver.h in libusb, at least not the version I had to work with. I took your usbtiny.h from avrdude and created it. It was missing some defines that I figured out by looking at the usbtiny firmware. It was mainly the numbers for the commands.
sgoadhouse
 
Posts: 6
Joined: Mon Jul 13, 2009 5:59 pm

Re: Using the SPI feature

by Cyberspice on Sat Jan 02, 2010 9:26 am

I've just been looking at the example code in the tarball (as I want to debug code in an ATTiny25 and I don't get much choice with the I/O). The usbdriver.h header is missing from the tarball so most of the defines are missing.

usb.h is the header file for libusb (v0.1, v1.0 has a different API) so you may need to install the libusb-dev package (or equivalent) on Linux for that. Since I'm OS X I'm going to steal it the header from my linux box. I have the library from installing the cross-pack tools.

I'm an embedded software engineer by default and I often have to debug, analyse and extend other people's code so I'm just going to look at avrdude and work out how it works from there. If you'd like a new example I'd be willing to write one.

Melanie
User avatar
Cyberspice
 
Posts: 1
Joined: Thu Jul 23, 2009 6:34 pm
Location: Yorkshire UK / Silicon Valley CA