testavr.c
author darius@Inchoate
Mon, 19 Jan 2009 22:54:19 +1030
changeset 71 553c061fda7c
parent 63 4d914a1fd487
permissions -rw-r--r--
Keep the newer GCC happy.
     1 /*
     2  * Test various AVR bits and pieces
     3  *
     4  * Copyright (c) 2008
     5  *      Daniel O'Connor <darius@dons.net.au>.  All rights reserved.
     6  *
     7  * Redistribution and use in source and binary forms, with or without
     8  * modification, are permitted provided that the following conditions
     9  * are met:
    10  * 1. Redistributions of source code must retain the above copyright
    11  *    notice, this list of conditions and the following disclaimer.
    12  * 2. Redistributions in binary form must reproduce the above copyright
    13  *    notice, this list of conditions and the following disclaimer in the
    14  *    documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
    20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    26  * SUCH DAMAGE.
    27  */
    28 
    29 #include <avr/io.h>
    30 #include <avr/interrupt.h>
    31 #include <avr/pgmspace.h>
    32 #include <stdio.h>
    33 #include <string.h>
    34 #include <ctype.h>
    35 #include <stdlib.h>
    36 #include <util/delay.h>
    37 #include <avr/wdt.h>
    38 
    39 #include "cons.h"
    40 #include "1wire.h"
    41 #ifdef WITHUSB
    42 #include "usb.h"
    43 #endif
    44 #include "tempctrl.h"
    45 #include "ds1307.h"
    46 
    47 /*
    48  * Mirror of the MCUCSR register, taken early during startup.
    49  */
    50 uint8_t mcucsr __attribute__((section(".noinit")));
    51 
    52 void		process_cmd(void);
    53 
    54 /*
    55  * Read out and reset MCUCSR early during startup.
    56  */
    57 void handle_mcucsr(void)
    58     __attribute__((section(".init3")))
    59     __attribute__((naked));
    60 void handle_mcucsr(void) {
    61     wdt_disable();
    62     mcucsr = MCUCSR;
    63     MCUCSR = 0;
    64 }
    65 
    66 int
    67 main(void) {
    68     /* Disable interrupts while we frob stuff */
    69     cli();
    70 
    71 #if 0
    72     /* Disable JTAG (yes twice) */
    73     MCUCSR |= _BV(JTD);
    74     MCUCSR |= _BV(JTD);
    75 #endif
    76 
    77 #ifdef WITHUSB
    78     /* USB data bus (7:0) */
    79     DDRA = 0x00;
    80     PORTA = 0x00;
    81     
    82     /* USB control (4:0) */
    83     DDRB = 0x0d;
    84     PORTB = 0x00;
    85 #else
    86     DDRA = 0xff;
    87     PORTA = 0x00;
    88 
    89     DDRB = 0x00;
    90     PORTB = 0x00;
    91 
    92 #endif    
    93     /* GPIO (0:7) */
    94     DDRC = 0xff;
    95     PORTC = 0x00;
    96 
    97     /* USART (0:1), IDBus (2:5), 485 (6:6), GPIO (7:7) */
    98     DDRD = 0xf7;
    99     PORTD = 0xf7;
   100 
   101 #ifndef WITHUSB
   102     /* Beep
   103      *
   104      * Fpwm = Fclk / (N * 510)
   105      *      = 16e6 / (8 * 510)
   106      *      = 3921Hz
   107      *
   108      * Behind ifndef because PB3 is A0 on PDI chip
   109      *
   110      * Phase correct PWM, non-inverted output, divide by 8 */
   111     TCCR0 = _BV(WGM00) | _BV(WGM11) | _BV(COM00) | _BV(COM01) | _BV(CS01);
   112     OCR0 = 128;
   113 #endif
   114 
   115     /* Set up the one wire stuff */
   116     OWInit();
   117 
   118     /* Setup IIC */
   119     ds1307_init();
   120     
   121     /* Init UART */
   122     cons_init();
   123     
   124     /* Init temperature control stuff */
   125     tempctrl_init();
   126 
   127     printf_P(PSTR("\r\n\r\n===============\r\n"
   128 		  "Inited!\r\n\r\n"));
   129 
   130     if ((mcucsr & _BV(PORF)) == _BV(PORF))
   131 	printf_P(PSTR("Power on reset\r\n"));
   132 
   133     if ((mcucsr & _BV(EXTRF)) == _BV(EXTRF))
   134 	printf_P(PSTR("External reset\r\n"));
   135 
   136     if ((mcucsr & _BV(BORF)) == _BV(BORF))
   137 	printf_P(PSTR("Brown-out reset\r\n"));
   138 
   139     if ((mcucsr & _BV(WDRF)) == _BV(WDRF))
   140 	printf_P(PSTR("Watchdog reset\r\n"));
   141 
   142     if ((mcucsr & _BV(JTRF)) == _BV(JTRF))
   143 	printf_P(PSTR("JTAG reset\r\n"));
   144 
   145     /* Ready to go! */
   146     sei();
   147 
   148     /*
   149      * Enable the watchdog with the largest prescaler.  Will cause a
   150      * watchdog reset after approximately 2 s @ Vcc = 5 V
   151      *
   152      * Gets reset in the loop below and in the tempctrl.c timer IRQ
   153      */
   154     wdt_enable(WDTO_2S);
   155 
   156 #ifdef WITHUSB
   157     printf_P(PSTR("Calling usb_init\r\n"));
   158     usb_init();
   159     printf_P(PSTR("done\r\n"));
   160     _delay_us(1000);
   161 #endif
   162     printf_P(PSTR("> "));
   163     cmd.state = 0;
   164     
   165     /* Wait for user input or an "interrupt" */
   166     while (1) {
   167 	wdt_reset();
   168 
   169 	tempctrl_update();
   170 	
   171 	if (cmd.state == 255) {
   172 	    process_cmd();
   173 	    printf_P(PSTR("> "));
   174 	    /* Allow new characters to be processed */
   175 	    cmd.state = 0;
   176 	}
   177 	
   178 #ifdef WITHUSB
   179 	if (!(PDICTL & _BV(PDIINT)))
   180 	    usb_intr();
   181 #endif
   182     }
   183 }
   184 
   185 void
   186 process_cmd(void) {
   187     uint8_t	ROM[8], crc, buf[9], temp;
   188     int8_t	i, arg;
   189     int16_t	t;
   190 
   191     /* User just pressed enter */
   192     if (cmd.len == 0)
   193 	return;
   194 	     
   195     if (!strcasecmp_P((char *)cmd.buf, PSTR("?")) ||
   196 	!strcasecmp_P((char *)cmd.buf, PSTR("help"))) {
   197         printf_P(PSTR("rs               Reset and check for presence\r\n"
   198 		      "sr               Search the bus for ROMs\r\n"
   199 		      "re               Read a bit\r\n"
   200 		      "rb               Read a byte\r\n"
   201 		      "wr bit           Write a bit\r\n"
   202 		      "wb byte          Write a byte (hex)\r\n"
   203 		      "wc cmd [ROMID]   Write command\r\n"
   204 		      "te ROMID         Read the temperature from a DS1820\r\n"
   205 		      "in port          Read from a port\r\n"
   206 		      "ou port val      Write to a port (val in hex)\r\n"
   207 		      "dd port [val]    Read/write DDR for a port (val in hex)\r\n"
   208 		      "rt ROMID	        Read DS2502 status page\r\n"
   209 		      "we ROMID adr val Write data into a DS2502 PROM (adr & val in hex)\r\n"
   210 		      "rr ROMID         Read DS2502 PROM\r\n"
   211 		      "zz               Reset MCU\r\n"
   212 		      "gc               Get time of day\r\n"
   213 		      "sc time          Set time of day (time is YYYY/MM/DD HH:MM:SS)\r\n"
   214 #ifdef WITHUSB
   215 		      "us               Generate USB data\r\n"
   216 #endif
   217 		      "tc ...           Temperature control related (tc help for more)\r\n"));
   218 	
   219 	return;
   220     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("zz"), 2)) {
   221 	cli();
   222 	wdt_enable(WDTO_15MS);
   223 	for (;;)
   224 	    ;
   225     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rs"), 2)) {
   226 	printf_P(PSTR("Resetting... "));
   227 	    
   228 	if (OWTouchReset() == 1)
   229 	    printf_P(PSTR("No presence pulse found\r\n"));
   230 	else
   231 	    printf_P(PSTR("Presence pulse found\r\n"));
   232     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("re"), 2)) {
   233 	if (OWReadBit())
   234 	    printf_P(PSTR("Read a 1\r\n"));
   235 	else
   236 	    printf_P(PSTR("Read a 0\r\n"));
   237     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rb"), 2)) {
   238 	printf_P(PSTR("Read a 0x%02x\r\n"), OWReadByte());
   239     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wr"), 2)) {
   240 	arg = strtol((char *)cmd.buf + 3, (char **)NULL, 10);
   241 	OWWriteBit(arg);
   242 	printf_P(PSTR("Wrote a %c\r\n"), arg ? '1' : '0');
   243     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wb"), 2)) {
   244 	arg = (int)strtol((char *)cmd.buf + 3, (char **)NULL, 16); 
   245 	OWWriteByte(arg);
   246     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rt"), 2)) {
   247 	if (sscanf_P((char *)cmd.buf, PSTR("rt %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), 
   248 		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
   249 		     &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) {
   250 	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
   251 	    return;
   252 	}
   253 	
   254 	if (ROM[0] != OW_FAMILY_ROM) {
   255 	    printf_P(PSTR("ROM specified isn't a DS2502\r\n"));
   256 	    return;
   257 	}
   258 
   259 	if (OWTouchReset() != 0) {
   260 	    printf_P(PSTR("No presence\r\n"));
   261 	    return;
   262 	}
   263 	
   264 	crc = 0;
   265 
   266 	OWCRC(OW_READ_STATUS, &crc);
   267 	OWSendCmd(ROM, OW_READ_STATUS);
   268 
   269 	OWWriteByte(0x00);
   270 	OWCRC(0x00, &crc);
   271 
   272 	OWWriteByte(0x00);
   273 	OWCRC(0x00, &crc);
   274 	
   275 	if (crc != OWReadByte()) {
   276 	    printf_P(PSTR("CRC mismatch on command & address\r\n"));
   277 	    return;
   278 	}
   279 	
   280 	crc = 0;
   281 	for (i = 0; i < 8; i++) {
   282 	    temp = OWReadByte();
   283 	    printf_P(PSTR("%02x "), temp);
   284 	    OWCRC(temp, &crc);
   285 	}
   286 	printf_P(PSTR("\r\n"));
   287 	if (crc != OWReadByte()) {
   288 	    printf_P(PSTR("CRC mismatch on data\r\n"));
   289 	    return;
   290 	}
   291     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("we"), 2)) {
   292 	uint8_t	adr, data;
   293 	
   294 	if (sscanf_P((char *)cmd.buf, PSTR("we %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhx %hhx"),
   295 		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
   296 		     &ROM[4], &ROM[5], &ROM[6], &ROM[7],
   297 		     &adr, &data) != 10) {
   298 	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
   299 	    return;
   300 	}
   301 
   302 	if (ROM[0] != OW_FAMILY_ROM) {
   303 	    printf_P(PSTR("ID specified isn't a ROM\r\n"));
   304 	    return;
   305 	}
   306 
   307 	if (OWTouchReset() != 0) {
   308 	    printf_P(PSTR("No presence\r\n"));
   309 	    return;
   310 	}
   311 
   312 	printf_P(PSTR("OWProgROM returned %S\r\n"), OWProgROM_Status[OWProgROM(ROM, buf[0], 2, &buf[1], 0, 0)]);
   313     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rr"), 2)) {
   314 	if (sscanf_P((char *)cmd.buf, PSTR("rr %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"),
   315 		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
   316 		     &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) {
   317 	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
   318 	    return;
   319 	}
   320 
   321 	if (ROM[0] != OW_FAMILY_ROM) {
   322 	    printf_P(PSTR("ROM specified isn't a ROM\r\n"));
   323 	    return;
   324 	}
   325 
   326 	crc = 0;
   327 	OWSendCmd(ROM, OW_READ_MEMORY);
   328 	OWCRC(OW_READ_MEMORY, &crc);
   329 
   330 	OWWriteByte(0x00);
   331 	OWCRC(0x00, &crc);
   332 
   333 	OWWriteByte(0x00);
   334 	OWCRC(0x00, &crc);
   335 
   336 	if (crc != OWReadByte()) {
   337 	    printf_P(PSTR("CRC mismatch on command & address\r\n"));
   338 	    return;
   339 	}
   340 
   341 	crc = 0;
   342 	for (buf[0] = 0; buf[0] < 128; buf[0]++) {
   343 	    buf[1] = OWReadByte();
   344 	    if (buf[0] > 0) {
   345 		if (buf[0] % 16 != 0)
   346 		    printf_P(PSTR(" "));
   347 		else
   348 		    printf_P(PSTR("\r\n"));
   349 	    }
   350 	    
   351 	    printf_P(PSTR("%02x"), buf[1]);
   352 	    OWCRC(buf[1], &crc);
   353 	}
   354 	printf_P(PSTR("\r\n"));
   355 	if (crc != OWReadByte()) {
   356 	    printf_P(PSTR("CRC mismatch on data\r\n"));
   357 	    return;
   358 	}
   359 	
   360     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wc"), 2)) {
   361 	uint8_t c;
   362 	
   363 	i = sscanf_P((char *)cmd.buf, PSTR("wc %hhx %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"),
   364 		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
   365 		     &ROM[4], &ROM[5], &ROM[6], &ROM[7],
   366 		     &c);
   367 	
   368 	if (i != 1 && i != 9) {
   369 	    printf_P(PSTR("Incorrect usage\r\n"));
   370 	    return;
   371 	}
   372 	    
   373 	if (i == 1) {
   374 	    OWSendCmd(i == 1 ? NULL : ROM, c);
   375 	    return;
   376 	}
   377     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("te"), 2)) {
   378 	if (sscanf_P((char *)cmd.buf, PSTR("te %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), 
   379 		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
   380 		     &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) {
   381 	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
   382 	    return;
   383 	}
   384 
   385 	t = OWGetTemp(ROM);
   386 	switch (t) {
   387 	    case OW_TEMP_WRONG_FAM:
   388 		printf_P(PSTR("ROM specified isn't a temperature sensor\r\n"));
   389 		break;
   390 
   391 	    case OW_TEMP_CRC_ERR:
   392 		printf_P(PSTR("CRC mismatch\r\n"));
   393 		break;
   394 
   395 	    case OW_TEMP_NO_ROM:
   396 		printf_P(PSTR("No ROM found\r\n"));
   397 		break;
   398 
   399 	    default:
   400 		printf_P(PSTR("%d.%02d\r\n"), GETWHOLE(t), GETFRAC(t));
   401 		break;
   402 	}
   403     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("sr"), 2)) {
   404 	memset(ROM, 0, 8);
   405 
   406 	i = OWFirst(ROM, 1, 0);
   407 	do {
   408 	    switch (i) {
   409 		case OW_BADWIRE:
   410 		    printf_P(PSTR("Presence pulse, but no module found, bad module/cabling?\r\n"));
   411 		    break;
   412 
   413 		case OW_NOPRESENCE:
   414 		    printf_P(PSTR("No presence pulse found\r\n"));
   415 		    break;
   416 		    
   417 		case OW_BADCRC:
   418 		    printf_P(PSTR("Bad CRC\r\n"));
   419 		    break;
   420 
   421 		case OW_NOMODULES:
   422 		case OW_FOUND:
   423 		    break;
   424 		    
   425 		default:
   426 		    printf_P(PSTR("Unknown error from 1 wire library\r\n"));
   427 		    break;
   428 	    }
   429 		
   430 	    if (i != OW_FOUND)
   431 		break;
   432 
   433 	    for (i = 0; i < 8; i++)
   434 		printf_P(PSTR("%02x%S"), ROM[i], i == 7 ? PSTR("\r\n") : PSTR(":"));
   435 
   436 	    i = OWNext(ROM, 1, 0);
   437 	} while (1);
   438     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("in"), 2)) {
   439 	uint8_t inp;
   440 	    
   441 	switch (tolower(cmd.buf[3])) {
   442 	    case 'a':
   443 		inp = PINA;
   444 		break;
   445 		
   446 	    case 'b':
   447 		inp = PINB;
   448 		break;
   449 		
   450 	    case 'c':
   451 		inp = PINC;
   452 		break;
   453 		
   454 	    case 'd':
   455 		inp = PIND;
   456 		break;
   457 		
   458 	    default:
   459 		printf_P(PSTR("Unknown port\r\n"));
   460 		return;
   461 	}
   462 	printf_P(PSTR("0x%02x\r\n"), inp);
   463     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("ou"), 2)) {
   464 	char port;
   465 	int val;
   466 	
   467 	if (sscanf_P((char *)cmd.buf, PSTR("ou %c %x"), &port, &val) != 2) {
   468 	    printf_P(PSTR("Unable to parse ou arguments\r\n"));
   469 	    return;
   470 	}
   471 	
   472 	switch (port) {
   473 	    case 'a':
   474 		PORTA = val & 0xff;
   475 		break;
   476 		
   477 	    case 'b':
   478 		PORTB = val & 0xff;
   479 		break;
   480 		
   481 	    case 'c':
   482 		PORTC = val & 0xff;
   483 		break;
   484 		
   485 	    case 'd':
   486 		PORTD = val & 0xff;
   487 		break;
   488 		
   489 	    default:
   490 		printf_P(PSTR("Unknown port\r\n"));
   491 		return;
   492 	}
   493 	printf_P(PSTR("PORT%c <= 0x%02x\r\n"), toupper(port), val);
   494     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("dd"), 2)) {
   495 	char port;
   496 	uint8_t val;
   497 	int num;
   498 	
   499 	num = sscanf_P((char *)cmd.buf, PSTR("dd %c %x"), &port, &val);
   500 	
   501 	if (num != 2 && num != 3) {
   502 	    printf_P(PSTR("Unable to parse dd arguments\r\n"));
   503 	    return;
   504 	}
   505 	
   506 	if (num == 2) {
   507 	    switch (port) {
   508 		case 'a':
   509 		    val = DDRA;
   510 		    break;
   511 
   512 		case 'b':
   513 		    val = DDRB;
   514 		    break;
   515 
   516 		case 'c':
   517 		    val = DDRC;
   518 		    break;
   519 		    
   520 		case 'd':
   521 		    val = DDRD;
   522 		    break;
   523 		
   524 		default:
   525 		    printf_P(PSTR("Unknown port\r\n"));
   526 		    return;
   527 	    }
   528 	    printf_P(PSTR("DDR%c => 0x%02x\r\n"), toupper(port), val);
   529 	} else {
   530 	    switch (port) {
   531 		case 'a':
   532 		    DDRA = val & 0xff;
   533 		    break;
   534 		
   535 		case 'b':
   536 		    DDRB = val & 0xff;
   537 		    break;
   538 		
   539 		case 'c':
   540 		    DDRC = val & 0xff;
   541 		    break;
   542 		
   543 		case 'd':
   544 		    DDRD = val & 0xff;
   545 		    break;
   546 		
   547 		default:
   548 		    printf_P(PSTR("Unknown port\r\n"));
   549 		    return;
   550 	    }
   551 	    printf_P(PSTR("DDR%c <= 0x%02x\r\n"), toupper(port), val);
   552 	}
   553     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("tc"), 2)) {
   554 	tempctrl_cmd((char *)cmd.buf);
   555 #ifdef WITHUSB
   556     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("us"), 2)) {
   557 	usb_gendata();
   558 #endif
   559     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("gc"), 2)) {
   560 	ds1307_printtime(PSTR(""), PSTR("\r\n"));
   561     } else if (!strncasecmp_P((char *)cmd.buf, PSTR("sc"), 2)) {
   562 	if (cmd.len < 17) {
   563 	    printf_P(PSTR("Command not long enough\r\n"));
   564 	} else {
   565 	    if (ds1307_settod((char *)cmd.buf + 3) != 1)
   566 		printf_P(PSTR("Unable to set time of day\r\n"));
   567 	}
   568     } else {
   569 	printf_P(PSTR("Unknown command, help for a list\r\n"));
   570     }
   571 }
   572