Commit 0a764c4ef24512959bcbb47eb905470a113fa856
authorMichel Pollet <buserror@gmail.com>
Thu, 24 Dec 2009 16:59:33 +0000 (16:59 +0000)
committerMichel Pollet <buserror@gmail.com>
Thu, 24 Dec 2009 16:59:33 +0000 (16:59 +0000)
Can program simduino with avrdude!
See the readme for the howto

Signed-off-by: Michel Pollet <buserror@gmail.com>
6 files changed:
examples/board_simduino/Makefile [new file with mode: 0644]
examples/board_simduino/README
examples/board_simduino/atmega328p_dummy_blinky.c [new file with mode: 0644]
examples/board_simduino/simduino.c [new file with mode: 0644]
examples/parts/uart_udp.c
examples/parts/uart_udp.h

diff --git a/examples/board_simduino/Makefile b/examples/board_simduino/Makefile
new file mode 100644 (file)
index 0000000..6d81178
--- /dev/null
@@ -0,0 +1,47 @@
+# 
+#      Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+#
+#      This file is part of simavr.
+#
+#      simavr is free software: you can redistribute it and/or modify
+#      it under the terms of the GNU General Public License as published by
+#      the Free Software Foundation, either version 3 of the License, or
+#      (at your option) any later version.
+#
+#      simavr is distributed in the hope that it will be useful,
+#      but WITHOUT ANY WARRANTY; without even the implied warranty of
+#      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#      GNU General Public License for more details.
+#
+#      You should have received a copy of the GNU General Public License
+#      along with simavr.  If not, see <http://www.gnu.org/licenses/>.
+
+board= simduino
+firm_src = ${wildcard atmega*.c}
+firmware = ${firm_src:.c=.hex}
+simavr = ../../
+
+SHELL   = /bin/bash
+
+IPATH = .
+IPATH += ../parts
+IPATH += ${simavr}/include
+IPATH += ${simavr}/simavr/sim
+
+VPATH = .
+VPATH += ../parts
+
+LDFLAGS += -lglut -lpthread
+
+all: obj ${firmware} ${board}
+
+include ${simavr}/Makefile.common
+
+${board} : ${OBJ}/button.o
+${board} : ${OBJ}/uart_udp.o
+${board} : ${OBJ}/${board}.o
+       @echo LD $@
+       @gcc -MD ${CFLAGS} -o $@ $^ $(LDFLAGS) ${simavr}/simavr/libsimavr.a
+
+clean:
+       rm -rf obj *.a *.axf ${board} *.vcd
index e7ac83a9f5a322e01ff862db1f364590b3d12631..fe6dd698c482de3680dada75e2c935ca6df03261 100644 (file)
@@ -1,8 +1,73 @@
 
-It's not working. don't get all excited. It loads and run the bootloader, but
-thats all.
-It /will/ work at some point, but it's not. It's missing a heck of a lot.
+This will emulate an arduino. Right now it loads the bootloader, then wait on it's "serial port"
+(a UDP socket on port 4321) until someone programs it... eventualy it timesout and run the previous
+app that was programmed.
 
-Told ya. forget about it ! :=)
+To actualy program it, you need "socat" to make a bridge between avrdude and simavr.
+
+% socat -d -d PTY UDP:localhost:4321
+       2009/12/24 16:19:26 socat[26974] N PTY is /dev/pts/10
+       2009/12/24 16:19:26 socat[26974] N opening connection to AF=2 127.0.0.1:4321
+       2009/12/24 16:19:26 socat[26974] N successfully connected from local address AF=2 127.0.0.1:48246
+       2009/12/24 16:19:26 socat[26974] N starting data transfer loop with FDs [3,3] and [6,6]
+
+Once that bridge is setup, launch simduino:
+
+% ./simduino
+       Starting atmega328 - flashend 7fff ramend 08ff e2end 03ff
+       atmega328 init
+       avr_flash_init init SPM 0057
+       read_ihex_file: ./ATmegaBOOT_168_atmega328.ihex, unsupported check type 03
+       Booloader 7800: 1950
+       uart_udp_init bridge on port 4321
+       UART-0 configured to 0010 = 58823 baud
+
+What that is done, you have a few seconds to program it:
+
+% avrdude -p m328p -c arduino -P /dev/pts/10 -U flash:w:atmega328p_dummy_blinky.hex
+
+       avrdude: AVR device initialized and ready to accept instructions
+       
+       Reading | ################################################## | 100% 0.01s
+       
+       avrdude: Device signature = 0x1e950f
+       avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
+                To disable this feature, specify the -D option.
+       avrdude: erasing chip
+       avrdude: reading input file "atmega328p_dummy_blinky.hex"
+       avrdude: input file atmega328p_dummy_blinky.hex auto detected as Intel Hex
+       avrdude: writing flash (394 bytes):
+       
+       Writing | ################################################## | 100% 0.15s
+       
+       avrdude: 394 bytes of flash written
+       avrdude: verifying flash memory against atmega328p_dummy_blinky.hex:
+       avrdude: load data flash data from input file atmega328p_dummy_blinky.hex:
+       avrdude: input file atmega328p_dummy_blinky.hex auto detected as Intel Hex
+       avrdude: input file atmega328p_dummy_blinky.hex contains 394 bytes
+       avrdude: reading on-chip flash data:
+       
+       Reading | ################################################## | 100% 0.13s
+       
+       avrdude: verifying ...
+       avrdude: 394 bytes of flash verified
+       
+       avrdude: safemode: Fuses OK
+       
+       avrdude done.  Thank you.
+
+simduino will display that:
+
+       Erasing page 0000 (128)
+       Writing page 0000 (128)
+       Erasing page 0001 (128)
+       Writing page 0001 (128)
+       Erasing page 0002 (128)
+       Writing page 0002 (128)
+       Erasing page 0003 (128)
+       Writing page 0003 (128)
+
+And then jump to the program that was programmed. The example doesn't do anything useful, it's
+a placeholder...
 
 Michel Pollet <buserror@gmail.com>
diff --git a/examples/board_simduino/atmega328p_dummy_blinky.c b/examples/board_simduino/atmega328p_dummy_blinky.c
new file mode 100644 (file)
index 0000000..e1a9680
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+       atmega328p_dummy_blinky.c
+
+       Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+       This file is part of simavr.
+
+       simavr is free software: you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation, either version 3 of the License, or
+       (at your option) any later version.
+
+       simavr is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with simavr.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifdef F_CPU
+#undef F_CPU
+#endif
+
+#define F_CPU 16000000
+
+#include <avr/io.h>
+#include <stdio.h>
+#include <avr/interrupt.h>
+#include <avr/eeprom.h>
+#include <avr/sleep.h>
+
+/*
+ * This demonstrate how to use the avr_mcu_section.h file
+ * The macro adds a section to the ELF file with useful
+ * information for the simulator
+ */
+#include "avr_mcu_section.h"
+AVR_MCU(F_CPU, "atmega328p");
+
+static int uart_putchar(char c, FILE *stream) {
+  if (c == '\n')
+    uart_putchar('\r', stream);
+  loop_until_bit_is_set(UCSR0A, UDRE0);
+  UDR0 = c;
+  return 0;
+}
+
+static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,
+                                         _FDEV_SETUP_WRITE);
+
+
+int main()
+{
+       stdout = &mystdout;
+
+       printf("Bootloader properly programmed, and ran me! Huzzah!\n");
+
+       // this quits the simulator, since interrupts are off
+       // this is a "feature" that allows running tests cases and exit
+       sleep_cpu();
+}
+
diff --git a/examples/board_simduino/simduino.c b/examples/board_simduino/simduino.c
new file mode 100644 (file)
index 0000000..6a3dcdc
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+       simduino.c
+
+       Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+       This file is part of simavr.
+
+       simavr is free software: you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation, either version 3 of the License, or
+       (at your option) any later version.
+
+       simavr is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with simavr.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <libgen.h>
+
+#include <GL/glut.h>
+#include <pthread.h>
+
+#include "sim_avr.h"
+#include "avr_ioport.h"
+#include "sim_elf.h"
+#include "sim_hex.h"
+#include "sim_gdb.h"
+#include "uart_udp.h"
+#include "sim_vcd_file.h"
+
+#include "button.h"
+
+button_t button;
+uart_udp_t uart_udp;
+int do_button_press = 0;
+avr_t * avr = NULL;
+avr_vcd_t vcd_file;
+uint8_t        pin_state = 0;  // current port B
+
+float pixsize = 64;
+int window;
+
+/*
+ * called when the AVR change any of the pins on port B
+ * so lets update our buffer
+ */
+void pin_changed_hook(struct avr_irq_t * irq, uint32_t value, void * param)
+{
+//     pin_state = (pin_state & ~(1 << irq->irq)) | (value << irq->irq);
+}
+
+void displayCB(void)           /* function called whenever redisplay needed */
+{
+       // OpenGL rendering goes here...
+       glClear(GL_COLOR_BUFFER_BIT);
+
+       // Set up modelview matrix
+       glMatrixMode(GL_MODELVIEW); // Select modelview matrix
+       glLoadIdentity(); // Start with an identity matrix
+
+       float grid = pixsize;
+       float size = grid * 0.8;
+    glBegin(GL_QUADS);
+       glColor3f(1,0,0);
+
+#if 0
+       for (int di = 0; di < 8; di++) {
+               char on = (pin_state & (1 << di)) != 0;
+               if (on) {
+                       float x = (di) * grid;
+                       float y = 0; //(si * grid * 8) + (di * grid);
+                       glVertex2f(x + size, y + size);
+                       glVertex2f(x, y + size);
+                       glVertex2f(x, y);
+                       glVertex2f(x + size, y);
+               }
+       }
+#endif
+    glEnd();
+    glutSwapBuffers();
+    //glFlush();                               /* Complete any pending operations */
+}
+
+void keyCB(unsigned char key, int x, int y)    /* called on key press */
+{
+       if (key == 'q')
+               exit(0);
+       static uint8_t buf[64];
+       switch (key) {
+               case 'q':
+               case 0x1f: // escape
+                       exit(0);
+                       break;
+               case ' ':
+                       do_button_press++; // pass the message to the AVR thread
+                       break;
+               case 'r':
+                       printf("Starting VCD trace\n");
+                       avr_vcd_start(&vcd_file);
+                       break;
+               case 's':
+                       printf("Stopping VCD trace\n");
+                       avr_vcd_stop(&vcd_file);
+                       break;
+       }
+}
+
+// gl timer. if the pin have changed states, refresh display
+void timerCB(int i)
+{
+       static uint8_t oldstate = 0xff;
+       // restart timer
+       glutTimerFunc(1000/64, timerCB, 0);
+#if 0
+       if (oldstate != pin_state) {
+               oldstate = pin_state;
+               glutPostRedisplay();
+       }
+#endif
+}
+
+static void * avr_run_thread(void * oaram)
+{
+       int b_press = do_button_press;
+
+       while (1) {
+               avr_run(avr);
+#if 0
+               if (do_button_press != b_press) {
+                       b_press = do_button_press;
+                       printf("Button pressed\n");
+                       button_press(&button, 1000000);
+               }
+#endif
+       }
+}
+
+
+int main(int argc, char *argv[])
+{
+       elf_firmware_t f;
+       const char * pwd = dirname(argv[0]);
+
+       avr = avr_make_mcu_by_name("atmega328p");
+       if (!avr) {
+               fprintf(stderr, "%s: Error creating the AVR core\n", argv[0]);
+               exit(1);
+       }
+       avr_init(avr);
+       avr->frequency = 16000000;
+
+       // this trick creates a file that contains /and keep/ the flash
+       // in the same state as it was before. This allow the bootloader
+       // app to be kept, and re-run if the bootloader doesn't get a
+       // new one
+       {
+               char path[256];
+               sprintf(path, "%s/%s", pwd, "simduino_flash.bin");
+
+               int fd = open(path, O_RDWR|O_CREAT, 0644);
+               if (fd < 0) {
+                       perror(path);
+                       exit(1);
+               }
+               ftruncate(fd, avr->flashend + 1);
+               uint8_t * mm = (uint8_t*)mmap(NULL, avr->flashend + 1 /* 32k is multiple of 4096 */,
+                               PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+               if (!mm) {
+                       perror(path);
+                       exit(1);
+               }
+
+               // reload bootloader anyway
+               free(avr->flash);
+               avr->flash = mm;
+
+               uint32_t base, size;
+               sprintf(path, "%s/%s", pwd, "ATmegaBOOT_168_atmega328.ihex");
+               uint8_t * boot = read_ihex_file(path, &size, &base);
+               if (!boot) {
+                       fprintf(stderr, "%s: Unable to load %s\n", argv[0], path);
+                       exit(1);
+               }
+               printf("Booloader %04x: %d\n", base, size);
+               memcpy(mm + base, boot, size);
+               free(boot);
+               avr->pc = base;
+               avr->codeend = avr->flashend;
+       }
+       //avr->trace = 1;
+
+       // even if not setup at startup, activate gdb if crashing
+       avr->gdb_port = 1234;
+       if (0) {
+               //avr->state = cpu_Stopped;
+               avr_gdb_init(avr);
+       }
+
+       uart_udp_init(avr, &uart_udp);
+       uart_udp_connect(&uart_udp, '0');
+
+       /*
+        * OpenGL init, can be ignored
+        */
+       glutInit(&argc, argv);          /* initialize GLUT system */
+
+       glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+       glutInitWindowSize(8 * pixsize, 1 * pixsize);           /* width=400pixels height=500pixels */
+       window = glutCreateWindow("Glut");      /* create window */
+
+       // Set up projection matrix
+       glMatrixMode(GL_PROJECTION); // Select projection matrix
+       glLoadIdentity(); // Start with an identity matrix
+       glOrtho(0, 8 * pixsize, 0, 1 * pixsize, 0, 10);
+       glScalef(1,-1,1);
+       glTranslatef(0, -1 * pixsize, 0);
+
+       glutDisplayFunc(displayCB);             /* set window's display callback */
+       glutKeyboardFunc(keyCB);                /* set window's key callback */
+       glutTimerFunc(1000 / 24, timerCB, 0);
+
+       // the AVR run on it's own thread. it even allows for debugging!
+       pthread_t run;
+       pthread_create(&run, NULL, avr_run_thread, NULL);
+
+       glutMainLoop();
+}
index cebf41c2e187e0e9d391d8ef1664ef1090cf8bd7..468d9c7ae5fae5ccc012e7fe48b337e15cb91932 100644 (file)
@@ -34,7 +34,7 @@
 #include "avr_uart.h"
 #include "sim_hex.h"
 
-DEFINE_FIFO(uint8_t,uart_udp_fifo, 128);
+DEFINE_FIFO(uint8_t,uart_udp_fifo, 512);
 
 /*
  * called when a byte is send via the uart on the AVR
@@ -42,6 +42,8 @@ DEFINE_FIFO(uint8_t,uart_udp_fifo, 128);
 static void uart_udp_in_hook(struct avr_irq_t * irq, uint32_t value, void * param)
 {
        uart_udp_t * p = (uart_udp_t*)param;
+//     printf("uart_udp_in_hook %02x\n", value);
+       uart_udp_fifo_write(&p->in, value);
 }
 
 /*
@@ -51,13 +53,15 @@ static void uart_udp_in_hook(struct avr_irq_t * irq, uint32_t value, void * para
 static void uart_udp_xon_hook(struct avr_irq_t * irq, uint32_t value, void * param)
 {
        uart_udp_t * p = (uart_udp_t*)param;
-       if (!p->xon)
-               printf("uart_udp_xon_hook\n");
+//     if (!p->xon)
+//             printf("uart_udp_xon_hook\n");
        p->xon = 1;
        // try to empty our fifo, the uart_udp_xoff_hook() will be called when
        // other side is full
        while (p->xon && !uart_udp_fifo_isempty(&p->out)) {
-               avr_raise_irq(p->irq + IRQ_UART_UDP_BYTE_OUT, uart_udp_fifo_read(&p->out));
+               uint8_t byte = uart_udp_fifo_read(&p->out);
+       //      printf("uart_udp_xon_hook send %02x\n", byte);
+               avr_raise_irq(p->irq + IRQ_UART_UDP_BYTE_OUT, byte);
        }
 }
 
@@ -67,8 +71,8 @@ static void uart_udp_xon_hook(struct avr_irq_t * irq, uint32_t value, void * par
 static void uart_udp_xoff_hook(struct avr_irq_t * irq, uint32_t value, void * param)
 {
        uart_udp_t * p = (uart_udp_t*)param;
-       if (p->xon)
-               printf("uart_udp_xoff_hook\n");
+//     if (p->xon)
+//             printf("uart_udp_xoff_hook\n");
        p->xon = 0;
 }
 
@@ -77,28 +81,42 @@ static void * uart_udp_thread(void * param)
        uart_udp_t * p = (uart_udp_t*)param;
 
        while (1) {
-               fd_set read_set;
-               int max;
+               fd_set read_set, write_set;
+               int max = p->s + 1;
                FD_ZERO(&read_set);
+               FD_ZERO(&write_set);
 
                FD_SET(p->s, &read_set);
-               max = p->s + 1;
+               if (!uart_udp_fifo_isempty(&p->in))
+                       FD_SET(p->s, &write_set);
 
-               struct timeval timo = { 0, 100 };       // short, but not too short interval
-               int ret = select(max, &read_set, NULL, NULL, &timo);
+               struct timeval timo = { 0, 500 };       // short, but not too short interval
+               int ret = select(max, &read_set, &write_set, NULL, &timo);
 
                if (FD_ISSET(p->s, &read_set)) {
-                       uint8_t buffer[1024];
+                       uint8_t buffer[512];
 
                        socklen_t len = sizeof(p->peer);
                        ssize_t r = recvfrom(p->s, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&p->peer, &len);
 
-                       hdump("udp", buffer, len);
+               //      hdump("udp recv", buffer, r);
 
                        // write them in fifo
                        uint8_t * src = buffer;
                        while (r-- && !uart_udp_fifo_isfull(&p->out))
                                uart_udp_fifo_write(&p->out, *src++);
+                       if (r > 0)
+                               printf("UDP dropped %d bytes\n", r);
+               }
+               if (FD_ISSET(p->s, &write_set)) {
+                       uint8_t buffer[512];
+                       // write them in fifo
+                       uint8_t * dst = buffer;
+                       while (!uart_udp_fifo_isempty(&p->in) && dst < (buffer+sizeof(buffer)))
+                               *dst++ = uart_udp_fifo_read(&p->in);
+                       socklen_t len = dst - buffer;
+                       size_t r = sendto(p->s, buffer, len, 0, (struct sockaddr*)&p->peer, sizeof(p->peer));
+               //      hdump("udp send", buffer, r);
                }
        }
 }
@@ -124,12 +142,20 @@ void uart_udp_init(struct avr_t * avr, uart_udp_t * p)
                return ;
        }
 
+       printf("uart_udp_init bridge on port %d\n", 4321);
+
        pthread_create(&p->thread, NULL, uart_udp_thread, p);
 
 }
 
 void uart_udp_connect(uart_udp_t * p, char uart)
 {
+       // disable the stdio dump, as we are sending binary there
+       uint32_t f = 0;
+       avr_ioctl(p->avr, AVR_IOCTL_UART_GET_FLAGS(uart), &f);
+       f &= ~AVR_UART_FLAG_STDIO;
+       avr_ioctl(p->avr, AVR_IOCTL_UART_SET_FLAGS(uart), &f);
+
        avr_irq_t * src = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUTPUT);
        avr_irq_t * dst = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_INPUT);
        avr_irq_t * xon = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XON);
index 20bdd74dacbe680dec6ccbac249f9a36ccffd726..10b06fedbcb2a6a7bae7ca0237906221ad7e2863 100644 (file)
@@ -33,7 +33,7 @@ enum {
        IRQ_UART_UDP_COUNT
 };
 
-DECLARE_FIFO(uint8_t,uart_udp_fifo, 128);
+DECLARE_FIFO(uint8_t,uart_udp_fifo, 512);
 
 typedef struct uart_udp_t {
        avr_irq_t *     irq;            // irq list