4 Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
6 This file is part of simavr.
8 simavr is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 simavr is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with simavr. If not, see <http://www.gnu.org/licenses/>.
32 #include "avr_ioport.h"
39 #include "reprap_gl.h"
44 #define __AVR_ATmega644__
45 #include "marlin/pins.h"
49 #include "marlin/Configuration.h"
52 * these are the sources of heat and cold to register to the heatpots
64 typedef struct ardupin_t {
65 uint32_t port : 7, pin : 3, analog : 1, adc : 3, pwm : 1, ardupin;
66 } ardupin_t, *ardupin_p;
68 ardupin_t arduidiot_644[32] = {
69 [ 0] = { .ardupin = 0, .port = 'B', .pin = 0 },
70 [ 1] = { .ardupin = 1, .port = 'B', .pin = 1 },
71 [ 2] = { .ardupin = 2, .port = 'B', .pin = 2 },
72 [ 3] = { .ardupin = 3, .port = 'B', .pin = 3 },
73 [ 4] = { .ardupin = 4, .port = 'B', .pin = 4 },
74 [ 5] = { .ardupin = 5, .port = 'B', .pin = 5 },
75 [ 6] = { .ardupin = 6, .port = 'B', .pin = 6 },
76 [ 7] = { .ardupin = 7, .port = 'B', .pin = 7 },
78 [ 8] = { .ardupin = 8, .port = 'D', .pin = 0 },
79 [ 9] = { .ardupin = 9, .port = 'D', .pin = 1 },
80 [10] = { .ardupin = 10, .port = 'D', .pin = 2 },
81 [11] = { .ardupin = 11, .port = 'D', .pin = 3 },
82 [12] = { .ardupin = 12, .port = 'D', .pin = 4 },
83 [13] = { .ardupin = 13, .port = 'D', .pin = 5 },
84 [14] = { .ardupin = 14, .port = 'D', .pin = 6 },
85 [15] = { .ardupin = 15, .port = 'D', .pin = 7 },
87 [16] = { .ardupin = 16, .port = 'C', .pin = 0 },
88 [17] = { .ardupin = 17, .port = 'C', .pin = 1 },
89 [18] = { .ardupin = 18, .port = 'C', .pin = 2 },
90 [19] = { .ardupin = 19, .port = 'C', .pin = 3 },
91 [20] = { .ardupin = 20, .port = 'C', .pin = 4 },
92 [21] = { .ardupin = 21, .port = 'C', .pin = 5 },
93 [22] = { .ardupin = 22, .port = 'C', .pin = 6 },
94 [23] = { .ardupin = 23, .port = 'C', .pin = 7 },
96 [24] = { .ardupin = 24, .port = 'A', .pin = 7, .analog = 1, .adc = 7 },
97 [25] = { .ardupin = 25, .port = 'A', .pin = 6, .analog = 1, .adc = 6 },
98 [26] = { .ardupin = 26, .port = 'A', .pin = 5, .analog = 1, .adc = 5 },
99 [27] = { .ardupin = 27, .port = 'A', .pin = 4, .analog = 1, .adc = 4 },
100 [28] = { .ardupin = 28, .port = 'A', .pin = 3, .analog = 1, .adc = 3 },
101 [29] = { .ardupin = 29, .port = 'A', .pin = 2, .analog = 1, .adc = 2 },
102 [30] = { .ardupin = 30, .port = 'A', .pin = 1, .analog = 1, .adc = 1 },
103 [31] = { .ardupin = 31, .port = 'A', .pin = 0, .analog = 1, .adc = 0 },
106 // gnu hackery to make sure the parameter is expanded
107 #define _TERMISTOR_TABLE(num) \
109 #define TERMISTOR_TABLE(num) \
110 _TERMISTOR_TABLE(num)
118 if (pins[ardupin].ardupin != ardupin) {
119 printf("%s pin %d isn't correct in table\n", __func__, ardupin);
122 struct avr_irq_t * irq = avr_io_getirq(avr,
123 AVR_IOCTL_IOPORT_GETIRQ(pins[ardupin].port), pins[ardupin].pin);
125 printf("%s pin %d PORT%C%d not found\n", __func__, ardupin, pins[ardupin].port, pins[ardupin].pin);
132 * called when the AVR change any of the pins on port B
133 * so lets update our buffer
137 struct avr_irq_t * irq,
141 printf("%s %d\n", __func__, value);
142 // pin_state = (pin_state & ~(1 << irq->irq)) | (value << irq->irq);
147 char avr_flash_path[1024];
148 int avr_flash_fd = 0;
150 // avr special flash initalization
151 // here: open and map a file to enable a persistent storage for the flash memory
152 void avr_special_init( avr_t * avr)
155 avr_flash_fd = open(avr_flash_path, O_RDWR|O_CREAT, 0644);
156 if (avr_flash_fd < 0) {
157 perror(avr_flash_path);
160 // resize and map the file the file
161 (void)ftruncate(avr_flash_fd, avr->flashend + 1);
162 ssize_t r = read(avr_flash_fd, avr->flash, avr->flashend + 1);
163 if (r != avr->flashend + 1) {
164 fprintf(stderr, "unable to load flash memory\n");
165 perror(avr_flash_path);
170 // avr special flash deinitalization
171 // here: cleanup the persistent storage
172 void avr_special_deinit( avr_t* avr)
175 lseek(avr_flash_fd, SEEK_SET, 0);
176 ssize_t r = write(avr_flash_fd, avr->flash, avr->flashend + 1);
177 if (r != avr->flashend + 1) {
178 fprintf(stderr, "unable to load flash memory\n");
179 perror(avr_flash_path);
182 uart_pty_stop(&reprap.uart_pty);
188 struct mg_connection *conn,
189 const struct mg_request_info *request_info)
191 if (event == MG_NEW_REQUEST) {
192 // Echo requested URI back to the client
193 mg_printf(conn, "HTTP/1.1 200 OK\r\n"
194 "Content-Type: text/plain\r\n\r\n"
195 "%s", request_info->uri);
196 return ""; // Mark as processed
202 #define MEGA644_GPIOR0 0x3e
205 reprap_relief_callback(
211 // printf("%s write %x\n", __func__, addr);
212 static uint16_t tick = 0;
233 uart_pty_init(avr, &r->uart_pty);
234 uart_pty_connect(&r->uart_pty, '0');
236 thermistor_init(avr, &r->therm_hotend, 0,
237 (short*)TERMISTOR_TABLE(TEMP_SENSOR_0),
238 sizeof(TERMISTOR_TABLE(TEMP_SENSOR_0)) / sizeof(short) / 2,
239 OVERSAMPLENR, 25.0f);
240 thermistor_init(avr, &r->therm_hotbed, 2,
241 (short*)TERMISTOR_TABLE(TEMP_SENSOR_BED),
242 sizeof(TERMISTOR_TABLE(TEMP_SENSOR_BED)) / sizeof(short) / 2,
243 OVERSAMPLENR, 30.0f);
244 thermistor_init(avr, &r->therm_spare, 1,
245 (short*)temptable_5, sizeof(temptable_5) / sizeof(short) / 2,
246 OVERSAMPLENR, 10.0f);
248 heatpot_init(avr, &r->hotend, "hotend", 28.0f);
249 heatpot_init(avr, &r->hotbed, "hotbed", 25.0f);
251 /* connect heatpot temp output to thermistors */
252 avr_connect_irq(r->hotend.irq + IRQ_HEATPOT_TEMP_OUT,
253 r->therm_hotend.irq + IRQ_TERM_TEMP_VALUE_IN);
254 avr_connect_irq(r->hotbed.irq + IRQ_HEATPOT_TEMP_OUT,
255 r->therm_hotbed.irq + IRQ_TERM_TEMP_VALUE_IN);
257 float axis_pp_per_mm[4] = DEFAULT_AXIS_STEPS_PER_UNIT; // from Marlin!
259 avr_irq_t * e = get_ardu_irq(avr, X_ENABLE_PIN, arduidiot_644);
260 avr_irq_t * s = get_ardu_irq(avr, X_STEP_PIN, arduidiot_644);
261 avr_irq_t * d = get_ardu_irq(avr, X_DIR_PIN, arduidiot_644);
262 avr_irq_t * m = get_ardu_irq(avr, X_MIN_PIN, arduidiot_644);
264 stepper_init(avr, &r->step_x, "X", axis_pp_per_mm[0], 100, 220, 0);
265 stepper_connect(&r->step_x, s, d, e, m, stepper_endstop_inverted);
268 avr_irq_t * e = get_ardu_irq(avr, Y_ENABLE_PIN, arduidiot_644);
269 avr_irq_t * s = get_ardu_irq(avr, Y_STEP_PIN, arduidiot_644);
270 avr_irq_t * d = get_ardu_irq(avr, Y_DIR_PIN, arduidiot_644);
271 avr_irq_t * m = get_ardu_irq(avr, Y_MIN_PIN, arduidiot_644);
273 stepper_init(avr, &r->step_y, "Y", axis_pp_per_mm[1], 100, 220, 0);
274 stepper_connect(&r->step_y, s, d, e, m, stepper_endstop_inverted);
277 avr_irq_t * e = get_ardu_irq(avr, Z_ENABLE_PIN, arduidiot_644);
278 avr_irq_t * s = get_ardu_irq(avr, Z_STEP_PIN, arduidiot_644);
279 avr_irq_t * d = get_ardu_irq(avr, Z_DIR_PIN, arduidiot_644);
280 avr_irq_t * m = get_ardu_irq(avr, Z_MIN_PIN, arduidiot_644);
282 stepper_init(avr, &r->step_z, "Z", axis_pp_per_mm[2], 20, 110, 0);
283 stepper_connect(&r->step_z, s, d, e, m, stepper_endstop_inverted);
286 avr_irq_t * e = get_ardu_irq(avr, E0_ENABLE_PIN, arduidiot_644);
287 avr_irq_t * s = get_ardu_irq(avr, E0_STEP_PIN, arduidiot_644);
288 avr_irq_t * d = get_ardu_irq(avr, E0_DIR_PIN, arduidiot_644);
290 stepper_init(avr, &r->step_e, "E", axis_pp_per_mm[3], 0, 0, 0);
291 stepper_connect(&r->step_e, s, d, e, NULL, 0);
296 int main(int argc, char *argv[])
300 for (int i = 1; i < argc; i++)
301 if (!strcmp(argv[i], "-d"))
303 avr = avr_make_mcu_by_name("atmega644");
305 fprintf(stderr, "%s: Error creating the AVR core\n", argv[0]);
308 // snprintf(avr_flash_path, sizeof(avr_flash_path), "%s/%s", pwd, "simduino_flash.bin");
309 strcpy(avr_flash_path, "reprap_flash.bin");
310 // register our own functions
311 avr->special_init = avr_special_init;
312 avr->special_deinit = avr_special_deinit;
314 avr->frequency = 20000000;
315 avr->aref = avr->avcc = avr->vcc = 5 * 1000; // needed for ADC
319 const char * fname = "/opt/reprap/tvrrug/Marlin.base/Marlin/applet/Marlin.elf";
320 elf_read_firmware(fname, &f);
322 printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, f.mmcu);
323 avr_load_firmware(avr, &f);
327 // snprintf(path, sizeof(path), "%s/%s", pwd, "ATmegaBOOT_168_atmega328.ihex");
328 strcpy(path, "marlin/Marlin.hex");
329 // strcpy(path, "marlin/bootloader-644-20MHz.hex");
330 uint8_t * boot = read_ihex_file(path, &size, &base);
332 fprintf(stderr, "%s: Unable to load %s\n", argv[0], path);
335 printf("Firmware %04x(%04x in AVR talk): %d bytes (%d words)\n", base, base/2, size, size/2);
336 memcpy(avr->flash + base, boot, size);
339 avr->codeend = avr->flashend;
343 // even if not setup at startup, activate gdb if crashing
344 avr->gdb_port = 1234;
346 printf("AVR is stopped, waiting on gdb on port %d. Use 'target remote :%d' in avr-gdb\n",
347 avr->gdb_port, avr->gdb_port);
348 avr->state = cpu_Stopped;
352 // Marlin doesn't loop, sleep, so we don't know when it's idle
353 // I changed Marlin to do a spurious write to the GPIOR0 register so we can trap it
354 avr_register_io_write(avr, MEGA644_GPIOR0, reprap_relief_callback, NULL);
356 reprap_init(avr, &reprap);
358 const char *options[] = {"listening_ports", "9090", NULL};
360 struct mg_context *ctx = mg_start(&mongoose_callback, NULL, options);
361 printf("mongoose %p\n", ctx);
365 pthread_create(&run, NULL, avr_run_thread, NULL);