view testavr.c @ 47:13a68734348b

Add watchdog timer.
author darius@Inchoate
date Mon, 20 Oct 2008 22:22:15 +1030
parents 5898fba6593c
children cb184206344d
line wrap: on
line source

/*
 * Test various AVR bits and pieces
 *
 * Copyright (c) 2008
 *      Daniel O'Connor <darius@dons.net.au>.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/wdt.h>

#include "cons.h"
#include "1wire.h"
#ifdef WITHUSB
#include "usb.h"
#endif
#include "tempctrl.h"

/*
 * Mirror of the MCUCSR register, taken early during startup.
 */
uint8_t mcucsr __attribute__((section(".noinit")));

void		process_cmd(void);

/*
 * Read out and reset MCUCSR early during startup.
 */
void handle_mcucsr(void)
    __attribute__((section(".init3")))
    __attribute__((naked));
void handle_mcucsr(void) {
    mcucsr = MCUCSR;
    MCUCSR = 0;
}

int
main(void) {
    /* Disable interrupts while we frob stuff */
    cli();

#if 0
    /* Disable JTAG (yes twice) */
    MCUCSR |= _BV(JTD);
    MCUCSR |= _BV(JTD);
#endif

#ifdef WITHUSB
    /* USB data bus (7:0) */
    DDRA = 0x00;
    PORTA = 0x00;
    
    /* USB control (4:0) */
    DDRB = 0x0d;
    PORTB = 0x00;
#else
    DDRA = 0xff;
    PORTA = 0x00;
#endif    
    /* GPIO (0:7) */
    DDRC = 0xff;
    PORTC = 0x00;

    /* USART (0:1), IDBus (2:5), 485 (6:6), GPIO (7:7) */
    DDRD = 0xf7;
    PORTD = 0xf7;

    /* Set up the one wire stuff */
    OWInit();

    /* Init UART */
    cons_init();
    
    printf_P(PSTR("\r\n\r\n===============\r\n"
		  "Inited!\r\n\r\n"));

    if ((mcucsr & _BV(PORF)) == _BV(PORF))
	printf_P(PSTR("Power on reset\r\n"));

    if ((mcucsr & _BV(EXTRF)) == _BV(EXTRF))
	printf_P(PSTR("External reset\r\n"));

    if ((mcucsr & _BV(BORF)) == _BV(BORF))
	printf_P(PSTR("Brown-out reset\r\n"));

    if ((mcucsr & _BV(WDRF)) == _BV(WDRF))
	printf_P(PSTR("Watchdog reset\r\n"));

    if ((mcucsr & _BV(JTRF)) == _BV(JTRF))
	printf_P(PSTR("JTAG reset\r\n"));

    tempctrl_init();
    
    /* Ready to go! */
    sei();

    /*
     * Enable the watchdog with the largest prescaler.  Will cause a
     * watchdog reset after approximately 2 s @ Vcc = 5 V
     *
     * Gets reset in the loop below and in the tempctrl.c timer IRQ
     */
    wdt_enable(WDTO_2S);

#ifdef WITHUSB
    printf_P(PSTR("Calling usb_init\r\n"));
    usb_init();
    printf_P(PSTR("done\r\n"));
    _delay_us(1000);
#endif
    printf_P(PSTR("> "));
    cmd.state = 0;
    
    /* Wait for user input or an "interrupt" */
    while (1) {
	wdt_reset();

	tempctrl_update();
	
	if (cmd.state == 255) {
	    process_cmd();
	    printf_P(PSTR("> "));
	    /* Allow new characters to be processed */
	    cmd.state = 0;
	}
	
#ifdef WITHUSB
	if (!(PDICTL & _BV(PDIINT)))
	    usb_intr();
#endif
    }
}

void
process_cmd(void) {
    uint8_t	ROM[8];
    int8_t	i, arg;
    uint8_t	crc, buf[9];
    int8_t	temp;
    uint16_t	tfrac;

    /* User just pressed enter */
    if (cmd.len == 0)
	return;
	     
    if (cmd.buf[0] == '?') {
        printf_P(PSTR("rs               Reset and check for presence\r\n"
		      "sr               Search the bus for ROMs\r\n"
		      "re               Read a bit\r\n"
		      "rb               Read a byte\r\n"
		      "wr  bit          Write a bit\r\n"
		      "wb  byte         Write a byte (hex)\r\n"
		      "wc  cmd [ROMID]  Write command\r\n"
		      "te  ROMID        Read the temperature from a DS1820\r\n"
		      "in  port         Read from a port\r\n"
		      "out port val     Write to a port\r\n"
		      "ddr port [val]   Read/write DDR for a port\r\n"
		      "tc ...		Temperature control related (tc help for more)\r\n"));
	
	return;
    }
	
    i = strlen((char *)cmd.buf);
    if (cmd.len < 2)
	goto badcmd;
	
    if (cmd.buf[0] == 'r' && cmd.buf[1] == 's') {
	printf_P(PSTR("Resetting... "));
	    
	if (OWTouchReset() == 1)
	    printf_P(PSTR("No presence pulse found\r\n"));
	else
	    printf_P(PSTR("Presence pulse found\r\n"));
    } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 'e') {
	if (OWReadBit())
	    printf_P(PSTR("Read a 1\r\n"));
	else
	    printf_P(PSTR("Read a 0\r\n"));
    } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 'b') {
	printf_P(PSTR("Read a 0x%02x\r\n"), OWReadByte());
    } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'r') {
	arg = strtol((char *)cmd.buf + 3, (char **)NULL, 10);
	OWWriteBit(arg);
	printf_P(PSTR("Wrote a %c\r\n"), arg ? '1' : '0');
    } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'b') {
	arg = (int)strtol((char *)cmd.buf + 3, (char **)NULL, 16); 
	OWWriteByte(arg);
    } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 't') {
	if (cmd.len < 26) {
	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
	    return;
	}

	if (OWTouchReset() != 0) {
	    printf_P(PSTR("No presence\r\n"));
	    return;
	}

	for (i = 0; i < 8; i++)
	    ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16);

	if (ROM[0] != OW_FAMILY_ROM) {
	    printf_P(PSTR("ROM specified isn't a DS2502\r\n"));
	    return;
	}

	if (OWTouchReset() != 0) {
	    printf_P(PSTR("No presence\r\n"));
	    return;
	}
	
	crc = 0;

	OWCRC(OW_READ_STATUS, &crc);
	OWSendCmd(ROM, OW_READ_STATUS);

	OWWriteByte(0x00);
	OWCRC(0x00, &crc);

	OWWriteByte(0x00);
	OWCRC(0x00, &crc);
	
	if (crc != OWReadByte()) {
	    printf_P(PSTR("CRC mismatch on command & address\r\n"));
	    return;
	}
	
	crc = 0;
	for (i = 0; i < 8; i++) {
	    temp = OWReadByte();
	    printf_P(PSTR("%02x "), temp);
	    OWCRC(temp, &crc);
	}
	printf_P(PSTR("\r\n"));
	if (crc != OWReadByte()) {
	    printf_P(PSTR("CRC mismatch on data\r\n"));
	    return;
	}
    } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'e') {
	if (cmd.len < 26) {
	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
	    return;
	}

	for (i = 0; i < 8; i++)
	    ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16);

	if (ROM[0] != OW_FAMILY_ROM) {
	    printf_P(PSTR("ROM specified isn't a ROM\r\n"));
	    return;
	}

	buf[0] = (int)strtol((char *)cmd.buf + 27, (char **)NULL, 16);	/* Address */
	buf[1] = (int)strtol((char *)cmd.buf + 30, (char **)NULL, 16);	/* Data .. */
	buf[2] = (int)strtol((char *)cmd.buf + 33, (char **)NULL, 16);
	
	if (OWTouchReset() != 0) {
	    printf_P(PSTR("No presence\r\n"));
	    return;
	}

	i = OWProgROM(ROM, buf[0], 2, &buf[1], 0, 0);
	printf_P(PSTR("OWProgROM returned %d\r\n"), i);
    } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 'r') {
	if (cmd.len < 26) {
	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
	    return;
	}

	for (i = 0; i < 8; i++)
	    ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16);

	if (ROM[0] != OW_FAMILY_ROM) {
	    printf_P(PSTR("ROM specified isn't a ROM\r\n"));
	    return;
	}

	crc = 0;
	OWSendCmd(ROM, OW_READ_MEMORY);
	OWCRC(OW_READ_MEMORY, &crc);

	OWWriteByte(0x00);
	OWCRC(0x00, &crc);

	OWWriteByte(0x00);
	OWCRC(0x00, &crc);

	if (crc != OWReadByte()) {
	    printf_P(PSTR("CRC mismatch on command & address\r\n"));
	    return;
	}

	crc = 0;
	for (buf[0] = 0; buf[0] < 128; buf[0]++) {
	    buf[1] = OWReadByte();
	    if (buf[0] > 0) {
		if (buf[0] % 16 != 0)
		    printf_P(PSTR(" "));
		else
		    printf_P(PSTR("\r\n"));
	    }
	    
	    printf_P(PSTR("%02x"), buf[1]);
	    OWCRC(buf[1], &crc);
	}
	printf_P(PSTR("\r\n"));
	if (crc != OWReadByte()) {
	    printf_P(PSTR("CRC mismatch on data\r\n"));
	    return;
	}
	
    } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'c') {
	if (cmd.len < 5) {
	    printf_P(PSTR("No arguments\r\n"));
	    return;
	}
	    
	arg = (int)strtol((char *)cmd.buf + 3, (char **)NULL, 16);
	if (arg == 0) {
	    printf_P(PSTR("Unparseable command\r\n"));
	    return;
	}

	if (i == 5) {
	    OWSendCmd(NULL, arg);
	    return;
	}
	    
	if (i < 29) {
	    printf_P(PSTR("Can't parse ROM ID\r\n"));
	    return;
	}
	for (i = 0; i < 8; i++)
	    ROM[i] = (int)strtol((char *)cmd.buf + 6 + (3 * i), (char **)NULL, 16);

	OWSendCmd(ROM, arg);
    } else if (cmd.buf[0] == 't' && cmd.buf[1] == 'e') {
	if (cmd.len < 26) {
	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
	    return;
	}

	for (i = 0; i < 8; i++)
	    ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16);

	if (ROM[0] != OW_FAMILY_TEMP) {
	    printf_P(PSTR("ROM specified isn't a temperature sensor\r\n"));
	    return;
	}
	    
	OWSendCmd(ROM, OW_CONVERTT_CMD);
	i = 0;
	/* Wait for the conversion */
	while (OWReadBit() == 0)
	    i = 1;


	OWSendCmd(ROM, OW_RD_SCR_CMD);
	crc = 0;
	for (i = 0; i < 9; i++) {
	    buf[i] = OWReadByte();
	    if (i < 8)
		OWCRC(buf[i], &crc);
	}
	    
	if (crc != buf[8]) {
	    printf_P(PSTR("CRC mismatch\r\n"));
	    return;
	}
	    
	/* 0	Temperature LSB
	 * 1	Temperature MSB
	 * 2	Th
	 * 3	Tl
	 * 4	Reserved
	 * 5	Reserved
	 * 6	Count Remain
	 * 7	Count per C
	 * 8	CRC
	 */
#if 0
	for (i = 0; i < 9; i++)
	    printf_P(PSTR("%d\r\n"), buf[i]);
#endif
	temp = buf[0];
	if (buf[1] & 0x80)
	    temp -= 256;
	temp >>= 1;

	tfrac = buf[7] - buf[6];
	tfrac *= (uint16_t)100;
	tfrac /= buf[7];
	tfrac += 75;
	if (tfrac < 100) {
	    temp--;
	} else {
	    tfrac -= 100;
	}
	    
	printf_P(PSTR("%d.%02d\r\n"), temp, tfrac);
    } else if (cmd.buf[0] == 's' && cmd.buf[1] == 'r') {
	memset(ROM, 0, 8);

	i = OWFirst(ROM, 1, 0);
	do {
	    switch (i) {
		case OW_BADWIRE:
		    printf_P(PSTR("Presence pulse, but no module found, bad module/cabling?\r\n"));
		    break;

		case OW_NOPRESENCE:
		    printf_P(PSTR("No presence pulse found\r\n"));
		    break;
		    
		case OW_BADCRC:
		    printf_P(PSTR("Bad CRC\r\n"));
		    break;

		case OW_NOMODULES:
		case OW_FOUND:
		    break;
		    
		default:
		    printf_P(PSTR("Unknown error from 1 wire library\r\n"));
		    break;
	    }
		
	    if (i != OW_FOUND)
		break;

	    for (i = 0; i < 8; i++)
		printf_P(PSTR("%02x%S"), ROM[i], i == 7 ? PSTR("\r\n") : PSTR(":"));

	    i = OWNext(ROM, 1, 0);
	} while (1);
    } else if (cmd.buf[0] == 'i' && cmd.buf[1] == 'n') {
	switch (tolower(cmd.buf[3])) {
	    case 'a':
		crc = PINA;
		break;
		
	    case 'b':
		crc = PINB;
		break;
		
	    case 'c':
		crc = PINC;
		break;
		
	    case 'd':
		crc = PIND;
		break;
		
	    default:
		printf_P(PSTR("Unknown port\r\n"));
		return;
	}
	printf_P(PSTR("0x%02x\r\n"), crc);
    } else if (cmd.buf[0] == 'o' && cmd.buf[1] == 'u') {
	crc = strtol((char *)cmd.buf + 8, (char **)NULL, 16);
	switch (tolower(cmd.buf[4])) {
	    case 'a':
		PORTA = crc;
		break;
		
	    case 'b':
		PORTB = crc;
		break;
		
	    case 'c':
		PORTC = crc;
		break;
		
	    case 'd':
		PORTD = crc;
		break;
		
	    default:
		printf_P(PSTR("Unknown port\r\n"));
		return;
	}
	printf_P(PSTR("PORT%c <= 0x%02x\r\n"), toupper(cmd.buf[4]), crc);
    } else if (cmd.buf[0] == 'd' && cmd.buf[1] == 'd') {
	crc = strtol((char *)cmd.buf + 8, (char **)NULL, 16);
	switch (tolower(cmd.buf[4])) {
	    case 'a':
		DDRA = crc;
		break;
		
	    case 'b':
		DDRB = crc;
		break;
		
	    case 'c':
		DDRC = crc;
		break;
		
	    case 'd':
		DDRD = crc;
		break;
		
	    default:
		printf_P(PSTR("Unknown port\r\n"));
		return;
	}
	printf_P(PSTR("0x%02x\r\n"), crc);
    } else if (cmd.buf[0] == 't' && cmd.buf[1] == 'c') {
	tempctrl_cmd((char *)cmd.buf);
#ifdef WITHUSB
    } else if (cmd.buf[0] == 'u' && cmd.buf[1] == 's') {
	usb_gendata();
#endif
    } else {
      badcmd:
	printf_P(PSTR("Unknown command, ? for a list\r\n"));
    }
}