LScreamer – Linux Wireless Firmware Downloader

Hello Sparkfun people!

Well I really liked the Screamer V2.0 from Sparkfun.com but the program was written in Visual Basic 6.  Since I’m a linux guy, I was running it thru virtual box and I needed to add support for the ATMEGA1280, so I had to choose between learning VB6 or something better.  I chose to write it in Python for linux, so I wouldn’t have to run the Windows XP image through VirtualBox.

LScreamer lets you scan the serial ports currently used by your system, and gives some good examples of how to use it.  I used the pocket programmer to download the bootloader via the ISP header, and I’ve made LScreamer to be fully compliant with Screamer V2.0.  It’s a command line utility, but it is very user friendly if your new to Linux or the command line.

I made it pretty easy to add new processors to it, and if you do, it would be great if you passed it onto me so I can update LScreamer.

Advertisements

10 thoughts on “LScreamer – Linux Wireless Firmware Downloader

  1. Hey Dustin-Robotics, I am currently using your atmega 1280 and atmega 168 bootloaders as a template for an atmega 128 bootloader. I was wondering if you could tell me what the PAGE_SIZE, incoming_page_data[512], and SPM_PAGESIZE variables stand for. I am looking at the data sheets for both the 168 and 1280 can can not find exactly these variables stand for. Thanks a bunch!

    • Hello Casey,

      Sorry about the delay. To answer your questions (albeit a little late ), these variables were created to process the data coming from the program that is writing the firmware (AVR-DUDE, LScreamer, etc.), so while the general page size is specified for the processors (ATMEGA1280 = 256 Words, ATMEGA168 = 128 Words), ATMEL didn’t design these bootloaders.

      -PAGE_SIZE: Amount of words that the processor expects for each page when self-programming the flash.
      -incoming_page_data[512]: This is an array that holds the data in the processor, until all of the data is received. Once it receives all the data, it starts to write this page of firmware to the processor’s flash. Notice that PAGE_SIZE is 256 words, and incoming_page_data is of length 512. This is because there are two bytes to each word. So the page size is 512 Bytes or 256 Words. In the datasheets they specify the page size in terms of words.
      -SPM_PAGESIZE is the same as PAGE_SIZE (notice PAGE_SIZE is 0x100U, which is hex for 256).

      I adapted the bootloader from sparkfun’s, as mentioned in the comments. 🙂

      • Thanks for the response Dustin,
        I actually gave up on the project because I was getting no where. After your recent reply I decided to start the project up again and still having no luck. Attached is my modified code for an Atmega 128. If you feel so inclined I would great appreciate a second pair of eye looking over it for any mistakes I may have made.

        #define F_CPU 1600000UL // added because the default value is 1000000UL in the delay function used by AVR studio

        #include

        #include

        #include

        //Define baud rate

        #define CPU_SPEED 16000000

        //#define BAUD 19200 //Works with internal osc

        #define BAUD 38400 //Works with internal osc

        //#define BAUD 57600 //Does not work with internal osc

        #define MYUBRR CPU_SPEED/16/BAUD-1 //(((((CPU_SPEED * 10) / (16L * BAUD)) + 5) / 10) – 1)

        //Here we calculate the wait period inside getch(). Too few cycles and the XBee may not be able to send the character in time. Too long and your sketch will take a long time to boot after powerup.

        #define MAX_CHARACTER_WAIT 15 //10 works. 20 works. 5 throws all sorts of retries, but will work.

        #define MAX_WAIT_IN_CYCLES ( ((MAX_CHARACTER_WAIT * 8) * CPU_SPEED) / BAUD )

        //I have found that flow control is not really needed with this implementation of wireless bootloading.

        //Adding flow control for wireless support

        //#define sbi(port_name, pin_number) (port_name |= 1<<pin_number)

        //#define cbi(port_name, pin_number) (port_name &= (uint8_t)~(1<> 8;

        UBRR0L = MYUBRR;

        UCSR0A = 0x00;

        UCSR0C = 0x06;

        UCSR0B = _BV(TXEN0) | _BV(RXEN0);

        /* Enable internal pull-up resistor on pin D0 (RX), in order

        to supress line noise that prevents the bootloader from

        timing out (DAM: 20070509) */

        /* feature added to the Arduino Mega –DC: 080930 */

        DDRE &= ~_BV(PINE0);

        PORTE |= _BV(PINE0);

        //set LED pin as output

        LED_DDR |= _BV(LED);

        //flash onboard LED to signal entering of bootloader

        flash_led(1);

        //Start bootloading process

        //while(1){

        putch(5); //Tell the world we can be bootloaded

        //}

        //Check to see if the computer responded

        uint32_t count = 0;

        while(!(UCSR0A & _BV(RXC0)))

        {

        count++;

        if (count > MAX_WAIT_IN_CYCLES)

        main_start();

        }

        if(UDR0 != 6) main_start(); //If the computer did not respond correctly with a ACK, we jump to user’s program

        while(1)

        {

        //Determine if the last received data was good or bad

        if (check_sum != 0) //If the check sum does not compute, tell computer to resend same line

        RESTART:

        putch(7); //Ascii character BELL

        else

        putch(‘T’); //Tell the computer that we are ready for the next line

        while(1) //Wait for the computer to initiate transfer

        {

        if (getch() == ‘:’) break; //This is the “gimme the next chunk” command

        if (retransmit_flag == TRUE) goto RESTART;

        }

        page_length_upper = getch(); //Get the length of this block

        page_length_lower = getch();

        page_length = (page_length_upper << 8 )+ page_length_lower;

        if (retransmit_flag == TRUE) goto RESTART;

        if (page_length_upper == 'S') //Check to see if we are done – this is the "all done" command

        {

        boot_rww_enable (); //Wait for any flash writes to complete?

        main_start();

        }

        //Get the memory address at which to store this block of data

        page_address.byte[0] = getch(); if (retransmit_flag == TRUE) goto RESTART;

        page_address.byte[1] = getch(); if (retransmit_flag == TRUE) goto RESTART;

        check_sum = getch(); //Pick up the check sum for error dectection

        if (retransmit_flag == TRUE) goto RESTART;

        for(i = 0 ; i < page_length ; i++) //Read the program data

        {

        incoming_page_data[i] = getch();

        if (retransmit_flag == TRUE) goto RESTART;

        }

        //Calculate the checksum

        for(i = 0 ; i < page_length ; i++)

        check_sum = check_sum + incoming_page_data[i];

        check_sum = check_sum + page_length;

        check_sum = check_sum + page_address.byte[0];

        check_sum = check_sum + page_address.byte[1];

        if(check_sum == 0) //If we have a good transmission, put it in ink

        onboard_program_write((uint32_t)page_address.word, incoming_page_data);

        }

        }

        #define SPM_PAGESIZE 256 //256 bytes or 128 words modified I've tried this with both words in bytes

        void onboard_program_write(uint32_t page, uint8_t *buf)

        {

        uint16_t i;

        //uint8_t sreg;

        // Disable interrupts.

        //sreg = SREG;

        //cli();

        //eeprom_busy_wait ();

        boot_page_erase (page);

        boot_spm_busy_wait (); // Wait until the memory is erased.

        for (i=0; i<SPM_PAGESIZE; i+=2)

        {

        // Set up little-endian word.

        uint16_t w = *buf++;

        w += (*buf++) << 8;

        boot_page_fill (page + i, w);

        }

        boot_page_write (page); // Store buffer in flash page.

        boot_spm_busy_wait(); // Wait until the memory is written.

        // Reenable RWW-section again. We need this if we want to jump back

        // to the application after bootloading.

        //boot_rww_enable ();

        // Re-enable interrupts (if they were ever enabled).

        //SREG = sreg;

        }

        void putch(char ch)

        {

        //Adding flow control – xbee testing

        //while( (PIND & (1< MAX_WAIT_IN_CYCLES) //

        {

        retransmit_flag = TRUE;

        break;

        }

        }

        //Adding flow control – xbee testing

        //sbi(PORTD, RTS); //Tell XBee to hold serial characters, we are busy doing other things

        return UDR0;

        }

        void flash_led(uint8_t count)

        {

        uint8_t i;

        for (i = 0; i < count; ++i) {

        LED_PORT |= _BV(LED);

        _delay_ms(1000);

        LED_PORT &= ~_BV(LED);

        _delay_ms(1000);

        }

        }

      • Hi Casey,

        Looking at the code, it seems that you haven’t copied all of it (its missing function prototypes such as :void putch(char);)

        I looked up the ATMega128 and it seems that it uses the same page size as the ATmega168 (256 bytes,http://www.atmel.com/dyn/resources/prod_documents/doc2546.pdf), so you’ll want incoming_page_data[256];

        Another thing to consider is that you need to make sure you set the fuse bits correctly in the Makefile, otherwise things won’t work. Looking into my makefile, it seems I didn’t really use it, but I did document the avrdude commands I used to first program fuses, then to download the bootloader (these are given in the comments block in the beginning of file).

        I would like to see the following to be able to help you more:
        1. Commands you used to set the fuse bits, download the firmware.
        2. Complete wireless bootloader c file.
        3. Perhaps a basic circuit (does it work with wired bootloading?)

  2. I think some of the text was altered by WordPess in my pass post.
    Attached is a link to the Pdf version of my modified bootloader stored on Google documents.
    https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=0B0DNbHqSaw46ODM2NTE3MGUtZjBmYS00YzM2LWI2MDUtOWI3MjIwOGUyMjUz&hl=en&authkey=CJyOs-UN

    As for the programming of the AVR chip, I have been using AVR Studio and the have enabled the following fuses:
    EXt. Crystal/Resonator High Freq;, Startup time 16K CK+ 64 ms; CKSEL=1111 SUT=11
    Boot Reset Vector Enabled(default address=$0000);[Bootrsr=0]
    Boot Flash section size=512 words Boot Start Address=$FE00;[BOOTSZ=11]
    Preserve EEPROM memory through the Chip Erase cycle; [EESAVE=0]
    Serial program downloading (SPI) enabled; [SPIEN=0]
    JTAG Interface Enabled; [JTAGEN=0]

    Avr Dude command looks like it would be:
    -U lfuse:w:0xff:m -U hfuse:w:0x96:m -U efuse:w:0xff:m

    As for the circuit, for the hardwired connection I am use a Max232 chip to connect RX0 and TD0 to my serial port.

    For the wireless circuit I am using xbee radios and the circuit designed by Lady Ada found here. http://www.ladyada.net/make/xbee/arduino.html
    I’ve tested both connections with a demo program and am able to Transmit and Receive data from the chip.

    I have tried using your LScreamer program and the screamer found here: http://akb77.com/g/avr/screamer/
    and both give me the same type of errors. They both seem to initially connect, but can not transmit the first data packet properly and the chip will keep telling the pc to rety sending the data packet. This will continue forever or the pc will stop saying it received the wrong signal from the chip.

    Sorry for the lengthy post but I wanted to address all of your questions, and thanks again for your help.

    Casey

    • Thanks for attaching the PDF!

      It looks like you know what you are doing regarding the fuses, and the serial connection. One thing to keep in mind is my LScreamer program was designed for Linux, and as such, I’m not sure if it would work in Windows. I don’t think it will work for the ATMega128, because the page size is similiar to the ATmega168, however the maximum flash is similiar to the ATmega1280. Once finals are over for me (Tuesday), I’ll go ahead and add the ATmega128 processor to LScreamer. But since I don’t have an actual ATMega128 processor, I’ll need you to test it for me (if your running it in Linux that is).

      The original sparkfun Screamer, and the screamer program you linked to (may be the same), don’t support the ATMega128 out of the box. If you can live with 16K of flash, then using the ATMega168 option for the sparkfun screamer or my LScreamer should work.

      A thing you may consider, is reducing the baudrate to 19200 (since that is the max baud rate of XBees in practice, and LScreamer and Screamer sends the firmware at 19200).

  3. Dustin,

    Good luck with finals, I just finished mine yesterday(Friday). I dual boot my system so I also run Linux(ubuntu). I modified both programs to transfer at the 38400 but will undo the changes I made. Since I have Linux and all the necessary software I will be able to test any changes you make.

    Casey

  4. Dustin,

    I’ve been working on the wireless bootloader for the Atmega128 and still having issues with it. I believe I was having timing issues so I switched to using the 8 MHz internal crystal and that seemed to help with all the resending request i was getting. Currently I am able to connect and transfer files but the chip doesn’t seem to reset and run the newly downloaded program. If i manually reset the chip after I downloaded a program the LED stays on and I think the bootloader is sitting there not doing anything. I am close to jsut giving up but figured I see what you think. Below is a list of links to my modified make files, LScreamer.py and ATMega128.c file. Please let me know if i have made any serious errors.

    https://docs.google.com/leaf?id=0B0DNbHqSaw46MGM4M2Q2ZjQtZjM5Yi00OGYwLWFiZGYtNzMyMGM4M2Y0YjI0&hl=en_US&authkey=CMWS84YD

    https://docs.google.com/leaf?id=0B0DNbHqSaw46ZWUzY2I1NDItODBkYy00OWI0LThlNjUtYWY2ZTUxYjZlNjI4&hl=en_US&authkey=CPSDhIsH

    https://docs.google.com/leaf?id=0B0DNbHqSaw46ZTgxMmY1NjYtYzVhMC00NWNlLWI0ZmYtOTQyNTIzMDgzYmNj&hl=en_US&authkey=CMr215wF

    Casey

    • Casey,

      One thing I would try is to verify that the downloaded firmware is actually being saved they way you want it to be. You can do this by reading the firmware that is currently on the processor, and comparing that hex file, to the hex file that you want to send to it.

      Using LScreamer, you can directly connect using serial to eliminate a sketchy wireless connection (for Arudino’s, can just connect using USB)

      I looked over the modified LScreamer.py, and the modifications you made are the ones that I would have made. I looked at the other two files and i couldn’t find anything explicitly wrong with them.

      Is there a board that you bought that had the ATMega128? I might consider getting one if it is a decent board.

      Good luck on getting this to work, it should be possible. I would look at copying the firmware from the device to see if it is all copied correctly. If it isn’t then, try to fix that. If it is, then look at your program. I wish I could help you more.

      Dustin

      • Dustin,

        How do you read the hex file saved to an AVR chip, in particular how do you tell AVR Dude to read the downloaded program and not the bootloader. I will try to download the program directly with a wired serial connection. The board I used can be found here http://www.gumstix.com/store/product_info.php?products_id=139, there is nothing special about the board except you can directly connect a embedded processor called a Gumstix Verdex. The Gumstix is a 32 bit processor running Linux so it good for robotic project requiring complicated calculations. If you have any other questions please feel free to ask.

        Casey

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s