Created
June 29, 2012 19:48
-
-
Save RickKimball/3020240 to your computer and use it in GitHub Desktop.
msp430 based avr910 AVR ISP programmer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* File : 910.c | |
* Author : Minifloat | |
* Project: Launchprog | |
* Version: 1.2 on 10 May 2012 | |
* | |
*/ | |
#include <msp430.h> | |
#include <stdint.h> | |
#include "devcodes.h" | |
#include "910.h" | |
#include "serial.h" | |
inline void usdelay(void) | |
{ | |
__delay_cycles((DELAYTIME)); | |
} | |
inline void delay(uint8_t delay) | |
{ | |
uint16_t i; | |
while (delay--) | |
{ | |
i = 64 * DELAYTIME; | |
while (i--) | |
asm(";"); | |
} | |
} | |
inline void pulse_sck(void) | |
{ | |
usdelay(); | |
set_sck(); | |
usdelay(); | |
clr_sck(); | |
usdelay(); | |
} | |
uint8_t uart_getc(void) | |
{ | |
return getchar(); | |
} | |
inline void uart_putc(uint8_t data) | |
{ | |
putchar(data); | |
} | |
void uart_puts(register const uint8_t *data) | |
{ | |
while (*data) | |
{ | |
uart_putc(*data); | |
data++; | |
} | |
} | |
uint8_t wrser(uint8_t send) | |
{ | |
uint8_t rcv = 0x00; | |
uint8_t mask; | |
for (mask = 0x80; mask != 0x00; mask /= 2) | |
{ | |
if(send & mask) | |
{ | |
set_mosi(); | |
} | |
else | |
{ | |
clr_mosi(); | |
} | |
if(rd_miso()) | |
rcv |= mask; | |
pulse_sck(); | |
} | |
return(rcv); | |
} | |
inline void spiinit(uint8_t device) | |
{ | |
uint8_t count; | |
set_rst(); | |
clr_sck(); | |
port_get(); | |
delay(0xff); | |
clr_rst(); | |
delay(0xff); | |
wrser(0xac); | |
wrser(0x53); | |
//only these devices show the sync fail?! | |
if ((device >= 20) && (device <= 0x7F)) | |
{ | |
count = 32; | |
do | |
{ | |
if (rdser() == 0x53) | |
break; | |
wrser(0x00); | |
pulse_sck(); | |
wrser(0xac); | |
wrser(0x53); | |
} | |
while (--count); | |
} | |
else | |
{ | |
wrser(0x00); | |
} | |
wrser(0x00); | |
delay(0x10); | |
} | |
inline void show_id(void) | |
{ | |
const static uint8_t id[] = "AVR ISP"; | |
uart_puts(id); | |
} | |
inline void init910(void) | |
{ | |
set_rst(); | |
led_init(); | |
ledr_off(); | |
ledg_off(); | |
port_release(); | |
} | |
inline void waitcmd(void) | |
{ | |
// device specific stuff | |
uint8_t device = 0, pgm_mode = 0, dev_ok = 1; | |
// switch command var | |
uint8_t sw; | |
// counting or GP variables | |
uint8_t i, j, k, l; | |
// r/w address | |
uint16_t addr = 0; | |
// the outer while loop | |
while (1) | |
{ | |
//ready for some action | |
ledg_on(); | |
dev_ok = 1; | |
// 0x1b is 'ESC' | |
while ((sw = uart_getc()) == 0x1b) | |
; | |
//busy becaus of some action | |
ledg_off(); | |
//commands taken from Serasidis' AVR910 | |
//commands from other sources are marked separately | |
switch (sw) | |
{ | |
case 'T': //device type | |
device = uart_getc(); | |
//dev_ok = 0; | |
//look up device in list | |
//i do this as the device is selected | |
//so i do not have to prove everytime | |
//a command after 'P' is executed | |
//as in Serasidis' original AVR910 v3.3 | |
for (i = 0; device_codes[i][0] != 0xFF ; i++) | |
{ | |
if(device == device_codes[i][0]) | |
{ | |
pgm_mode = device_codes[i][1]; | |
dev_ok = 1; | |
break; | |
} | |
else | |
{ | |
dev_ok = 0; | |
} | |
} | |
if (dev_ok) | |
{ | |
// found selected dev in list | |
uart_put_ret(); | |
} | |
else | |
{ | |
// didnt find device in list | |
uart_put_err(); | |
} | |
break; | |
case 'S': //Return software id | |
show_id(); | |
break; | |
case 'V': //Return SW version | |
uart_putc((uint8_t)SW_MAJOR); | |
uart_putc((uint8_t)SW_MINOR); | |
break; | |
case 'v': //Return HW version | |
uart_putc((uint8_t)HW_MAJOR); | |
uart_putc((uint8_t)HW_MINOR); | |
break; | |
case 't': //show supported devices | |
for (i = 0; device_codes[i][0] != 0xFF ; i++) | |
{ | |
uart_putc(device_codes[i][0]); | |
} | |
uart_putc(0); | |
break; | |
case 'p': //Return programmer type | |
uart_putc((uint8_t)'S'); | |
break; | |
case 'a': //Return address auto-increment | |
uart_putc((uint8_t)'Y'); | |
break; | |
case 'b': | |
//Return Blockmode capability(from Leidingers AVR910 v3.8) | |
//this device is not capable of block mode(no buffer avail) | |
//avrdude needs this info, otherwise the dude | |
//crashes with report "programmer not answering" | |
uart_putc((uint8_t)'N'); | |
break; | |
case 'x': //set LED ignored | |
uart_getc(); | |
uart_put_ret(); | |
break; | |
case 'y': //clear LED ignored | |
uart_getc(); | |
uart_put_ret(); | |
break; | |
default: | |
break; | |
} | |
//without a valid device | |
//commands below this won't work | |
if (!dev_ok) | |
{ | |
// no or no valid device was selected | |
// or errorneous opcode was given | |
uart_put_err(); | |
// continues the outer while loop | |
continue; | |
} | |
else | |
{ | |
// valid device was selected | |
switch (sw) | |
{ | |
case 'P': //enter programming mode | |
spiinit(device); | |
uart_put_ret(); | |
ledr_on(); | |
break; | |
case 'C': //write program memory hi-Byte | |
i = uart_getc(); | |
wrser(0x48); | |
wrser((uint8_t) (addr >> 8)); //addr.hi | |
wrser((uint8_t) (addr & 0xFF)); //addr.lo | |
wrser(i); | |
addr++; | |
if (!pgm_mode) | |
delay(0x20); | |
uart_put_ret(); | |
break; | |
case 'c': //write program memory lo-Byte | |
i = uart_getc(); | |
wrser(0x40); | |
wrser((uint8_t) (addr >> 8)); //addr.hi | |
wrser((uint8_t) (addr & 0xFF)); //addr.lo | |
wrser(i); | |
if (!pgm_mode) | |
delay(0x20); | |
uart_put_ret(); | |
break; | |
case 'R': //read program memory | |
wrser(0x28); | |
wrser((uint8_t) (addr >> 8)); //addr.hi | |
wrser((uint8_t) (addr & 0xFF)); //addr.lo | |
uart_putc(rdser()); | |
wrser(0x20); | |
wrser((uint8_t) (addr >> 8)); //addr.hi | |
wrser((uint8_t) (addr & 0xFF)); //addr.lo | |
uart_putc(rdser()); | |
addr++; | |
break; | |
case 'A': //load address | |
addr = 256 * uart_getc(); //read addr.hi | |
addr += uart_getc(); //read addr.lo | |
uart_put_ret(); | |
break; | |
case 'D': //write data memory | |
i = uart_getc(); | |
wrser(0xc0); | |
wrser((uint8_t) (addr >> 8)); //addr.hi | |
wrser((uint8_t) (addr & 0xFF)); //addr.lo | |
wrser(i); | |
delay(0x20); | |
addr++; | |
uart_put_ret(); | |
break; | |
case 'd': //read data memory | |
wrser(0xa0); | |
wrser((uint8_t) (addr >> 8)); //addr.hi | |
wrser((uint8_t) (addr & 0xFF)); //addr.lo | |
uart_putc(rdser()); | |
addr++; | |
break; | |
case 'L': //leave programming mode | |
port_release(); | |
set_rst(); | |
ledr_off(); | |
uart_put_ret(); | |
break; | |
case 'e': //chip erase | |
wrser(0xac); | |
wrser(0x80); | |
wrser(0x04); | |
wrser(0x00); | |
delay(0x30); | |
uart_put_ret(); | |
break; | |
case 'l' : //write lock bits | |
i = uart_getc(); | |
wrser(0xac); | |
wrser((i & 0x06) | 0xe0); | |
wrser(0x00); | |
wrser(0x00); | |
delay(0x30); | |
uart_put_ret(); | |
break; | |
case 's': //read signature bytes | |
for(i = 0x02; i != 0xFF; i--) | |
{ | |
wrser(0x30); | |
wrser(0x00); | |
wrser(i); | |
uart_putc(rdser()); | |
} | |
break; | |
case 'm': //write program memory page | |
wrser(0x4c); | |
wrser((uint8_t) (addr >> 8)); //addr.hi | |
wrser((uint8_t) (addr & 0xFF)); //addr.lo | |
wrser(0x00); | |
delay(0xFF); | |
uart_put_ret(); | |
break; | |
case ':': //universal command ":" | |
case '.': //universal command "." | |
i = uart_getc(); | |
j = uart_getc(); | |
k = uart_getc(); | |
l = (sw == ((uint8_t)':'))?0:uart_getc(); | |
wrser(i); | |
wrser(j); | |
wrser(k); | |
uart_putc(wrser(l)); | |
delay(0xFF); | |
uart_put_ret(); | |
break; | |
default: | |
//or errorneous opcode was given | |
//do we need this? | |
//uart_putc('?'); | |
break; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* File : 910.h | |
* Author : Minifloat | |
* Project: Launchprog | |
* Version: 1.2 on 10 May 2012 | |
* | |
*/ | |
#ifndef HEADER910 | |
#define HEADER910 | |
//version info | |
#define SW_MAJOR '3' | |
#define SW_MINOR '3' | |
#define HW_MAJOR '1' | |
#define HW_MINOR '0' | |
//delay val | |
#define DELAYTIME (F_CPU/1000000) | |
//portpin access macros | |
// LEDR = P1.0 the red led | |
// ~RESET = P1.3 there's also a button S2 to GND. | |
// MOSI = P1.4 | |
// MISO = P1.5 | |
// LEDG = P1.6 the green led | |
// SCK = P1.7 | |
#define LEDRPIN BIT0 | |
#define RESETPIN BIT3 | |
#define MOSIPIN BIT4 | |
#define MISOPIN BIT5 | |
#define LEDGPIN BIT6 | |
#define SCKPIN BIT7 | |
#define set_rst() P1OUT|=RESETPIN | |
#define clr_rst() P1OUT&=~RESETPIN | |
#define ledr_on() P1OUT|=LEDRPIN | |
#define ledr_off() P1OUT&=~LEDRPIN | |
#define ledg_on() P1OUT|=LEDGPIN | |
#define ledg_off() P1OUT&=~LEDGPIN | |
#define led_init() P1DIR|=LEDGPIN+LEDRPIN | |
#define port_get() P1DIR|=MOSIPIN+RESETPIN+SCKPIN | |
#define port_release() P1DIR&=~(MOSIPIN+RESETPIN+SCKPIN+MISOPIN) | |
#define set_sck() P1OUT|=SCKPIN | |
#define clr_sck() P1OUT&=~SCKPIN | |
#define set_mosi() P1OUT|=MOSIPIN | |
#define clr_mosi() P1OUT&=~MOSIPIN | |
#define rd_miso() (P1IN&MISOPIN) | |
//global variables | |
//delay func | |
inline void usdelay(void); | |
inline void delay(uint8_t dly); | |
//pulse sck one time | |
inline void pulse_sck(void); | |
//uart functions compatibility | |
uint8_t uart_getc(void); | |
void uart_putc(uint8_t data); | |
void uart_puts(const uint8_t *data); | |
//send CR | |
#define uart_put_ret() uart_putc(0x0d) | |
//send '?' | |
#define uart_put_err() uart_putc(0x3f) | |
//write read soft spi | |
uint8_t wrser(uint8_t send); | |
//read soft spi | |
#define rdser() wrser(0) | |
//enter programming mode | |
inline void spiinit(uint8_t device); | |
//show "AVR ISP" on serial line | |
inline void show_id(void); | |
//RESET marker of 910 | |
inline void init910(void); | |
//wait for a command | |
inline void waitcmd(void); | |
#endif //HEADER910 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* File : devcodes.h | |
* Author : Minifloat | |
* Project: Launchprog | |
* Version: 1.2 on 10 May 2012 | |
* | |
*/ | |
//These Device codes are directly taken from Serasidis' AVR910 | |
//i know i shouldn't put this in a header file only | |
//but now its more like using a asm .inc file | |
//Device codes and program mode table (0(zero)=byte mode, <>0=page mode) | |
//i.e. 'P' can be used for page mode for easier reading. | |
#ifndef DEVCODES_H | |
#define DEVCODES_H | |
#include <stdint.h> | |
static const uint8_t device_codes[][2] __attribute__((section(".infomem"))) = { | |
//AT90S1200 rev. A //From 0x00-0x0f unused yet | |
{0x10, 0}, | |
//AT90S1200 rev. B | |
{0x11, 0}, | |
//AT90S1200 rev. C | |
{0x12, 0}, | |
//AT90S1200 | |
{0x13, 0}, //From 0x14-0x1f unused yet | |
//AT90S2313 | |
{0x20, 0}, //From 0x21-0x27 unused yet | |
//AT90S4414 | |
{0x28, 0}, //From 0x29-0x2f unused yet | |
//AT90S4433 | |
{0x30, 0}, //From 0x31-0x33 unused yet | |
//AT90S2333 | |
{0x34, 0}, //From 0x35-0x37 unused yet | |
//AT90S8515 | |
{0x38, 0}, //0x39 unused yet | |
//ATmega8515 | |
{0x3A, (uint8_t)'P'}, | |
//ATmega8515 BOOT | |
{0x3B, (uint8_t)'P'}, //From 0x3c-0x40 unused yet | |
//ATmega103 | |
{0x41, (uint8_t)'P'}, | |
//ATmega603 | |
{0x42, (uint8_t)'P'}, | |
//ATmega128 | |
{0x43, (uint8_t)'P'}, | |
//ATmega128 BOOT | |
{0x44, (uint8_t)'P'}, | |
//ATmega64 | |
{0x45, (uint8_t)'P'}, // v1.40 | |
//ATmega64 BOOT | |
{0x46, (uint8_t)'P'}, // v1.40 0x47 unused yet | |
//AT90S2323 | |
{0x48, 0}, //From 0x49-0x4b unused yet | |
//AT90S2343 | |
{0x4C, 0}, //From 0x4d-0x4f unused yet | |
//0x50,0x51 used. From 0x52-0x54 unused yet | |
// | |
//ATtiny12 | |
{0x55, 0}, | |
//ATtiny15 | |
{0x56, 0}, //0x57 unused yet | |
//ATtiny19 | |
{0x58, 0}, //From 0x59-0x5b unused yet | |
//ATtiny28 | |
{0x5C, 0}, //0x5d unused yet | |
//ATtiny26 | |
{0x5E, (uint8_t)'P'}, //0x5f unused yet | |
// | |
//ATmega161 | |
{0x60, (uint8_t)'P'}, | |
//ATmega161 BOOT | |
{0x61, (uint8_t)'P'}, //0x62-0x63 unused yet | |
//ATmega163 | |
{0x64, (uint8_t)'P'}, | |
//ATmega83 | |
{0x65, (uint8_t)'P'}, | |
//ATmega163 BOOT | |
{0x66, (uint8_t)'P'}, | |
//ATmega83 BOOT | |
{0x67, (uint8_t)'P'}, | |
//AT90S8535 | |
{0x68, 0}, | |
//ATmega8535 | |
{0x69, (uint8_t)'P'}, // v1.40 From 0x6a-0x6b unused yet | |
//ATmega8535 BOOT?? | |
// {0x6a, (uint8_t)'P'}, | |
// | |
//AT90S4434 | |
{0x6C, 0}, //From 0x6d-0x6f unused yet | |
//AT90C8534 | |
{0x70, 0}, | |
//AT90C8544 | |
{0x71, 0}, | |
//ATmega32 | |
{0x72, (uint8_t)'P'}, | |
//ATmega32 BOOT | |
{0x73, (uint8_t)'P'}, | |
//ATmega16 | |
{0x74, (uint8_t)'P'}, | |
//ATmega16 BOOT | |
{0x75, (uint8_t)'P'}, | |
//ATmega8 | |
{0x76, (uint8_t)'P'}, | |
//ATmega8 BOOT | |
{0x77, (uint8_t)'P'}, | |
//ATmega169 | |
{0x78, (uint8_t)'P'}, // v1.40 | |
//ATmega169 BOOT | |
{0x79, (uint8_t)'P'}, // v1.40 From 0x7a-0x7f unused yet | |
//test | |
// {0x08, (uint8_t)'P'}, | |
// {0x09, (uint8_t)'P'}, | |
// {0x0a, (uint8_t)'P'}, | |
// {0x0b, (uint8_t)'P'}, | |
//These devices are not supported by this hardware | |
//ATtiny10 | |
// {0x51, 0}, | |
//ATtiny11 | |
// {0x50, 0}, | |
//AT89C1051 | |
// {0x80, 0}, | |
//AT89C2051 | |
// {0x81, 0}, //From 0x82-0x85 unused yet | |
//AT89S8252 | |
// {0x86, 0}, | |
//AT89S53 | |
// {0x87, 0}, //From 0x88-0x9f unused yet | |
//end_of_device_codes: | |
//.dw 0xffff | |
{0xFF, 0xFF} | |
//@@ | |
}; | |
#endif //DEVCODES_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* main.c - Launchpad compatible full-duplex software UART example program. | |
* | |
* This example program implements an async serial echo program. | |
* To test it, use a terminal program such as putty or | |
* hyperterminal, connect to the COM port associated with your | |
* launchpad device, and type away. Whatever you type will be | |
* echoed back to you. The default settings are 9600-8-N-1 | |
* as defined in the config.h file. | |
* | |
* The code illustrates how to utilize the full-duplex interrupt | |
* driven software UART routines from softserial.c | |
* | |
* CPU speed and baud rate are set in config.h. The software | |
* might drive the TX and RX signals up to 230400 baud | |
* depending on the accuracy of your SMCLK. To get a baud rate | |
* greater than 9600 you will have to use something like | |
* an FT232RL device and a fast CPU speed. Using the integrated | |
* COM port of the launchpad, the baud rate is limited to 9600 | |
* as stated in the launchpad user guide. | |
* | |
* This software monopolizes the TIMERA0_VECTOR and TIMERA1_VECTOR | |
* interrupts. This code assumes you are using a TI Launchpad | |
* with an msp430g2231 in the socket, and the external watch | |
* crystal soldered on the board. However it should work with | |
* any mps430 device you can put in the launchpad socket. It | |
* uses about 800 bytes of flash. | |
* | |
* This software is s mismash of various chunks of code | |
* available on the net, with my own special seasoning. Mostly | |
* inspired by Appnote sla307a, the arduino HardwareSerial.cpp | |
* source, and various postings on the TI e2e forum. | |
* | |
* License: Do with this code what you want. However, don't blame | |
* me if you connect it to a heart pump and it stops. This source | |
* is provided as is with no warranties. It probably has bugs!! | |
* You have been warned! | |
* | |
* Author: Rick Kimball | |
* email: rick@kimballsoftware.com | |
* Version: 1.00 Initial version 04-20-2011 | |
* Version: 1.01 cleanup 04-21-2011 | |
* | |
* Author: Minifloat | |
* Version: fork Launchprog 1.2 on 10 May 2012 | |
* | |
* Author: Rick Kimball | |
* Version: 1.2a - replaced async serial routines with blocking ones, use | |
* DCO @ precalibrated 1MHz instead of 32.768kHz xtal. | |
* Located the device code table in .infomem flash. This frees | |
* up more space in the main flash for code. Created a define | |
* "OUTPUT_CLOCKS" to make it easier to measure the clock speed | |
* in setup() with a frequency counter so no xtal is required. | |
* Modified delays so they are based on the F_CPU frequency. | |
*/ | |
/* comment minifloat: | |
* some "corrections" on header stuff | |
*/ | |
#include <msp430.h> | |
#include <stdint.h> | |
#include "serial.h" | |
#include "910.h" | |
#define _enable_interrupts _EINT | |
#define _disable_interrupts _DINT | |
/** | |
* setup() - initialize timers and clocks | |
*/ | |
void setup() { | |
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer | |
#if CALIBRATED | |
DCOCTL = 0x00; // Use factory pre-calibrated DCOCLK to 1MHz | |
BCSCTL1 = CALBC1_1MHZ; | |
DCOCTL = CALDCO_1MHZ; | |
DCOCTL += 7; // I tweaked this value to make the DCO go faster. My | |
// factory calibrated value was 977kHz. '7' gets me right | |
// on 1.00MHz. You should adjust for your chip's speed | |
// or you could use an XTAL and calibrate it yourself. | |
#else | |
// 16.025000 MHz on my chip, measured | |
DCOCTL = 0; | |
BCSCTL1 = XT2OFF | (1 << 3 | 1 << 2 | 1 << 1) ; | |
DCOCTL = (1 << 7 | 1 << 6 | 1 << 5); | |
#endif | |
init_serial(F_CPU/BAUD_RATE); // RX=P1.2, TX=P1.1 | |
#undef OUTPUT_CLOCKS // if defined, output clocks on pins so you can | |
// measure with oscilloscope or frequency counter | |
#ifdef OUTPUT_CLOCKS | |
P1DIR |= BIT0; P1SEL |= BIT0; // measure P1.0 for actual ACLK | |
P1DIR |= BIT4; P1SEL |= BIT4; // measure P1.4 for actual SMCLK | |
while( 1 ) { ; } // just stop here don't do anything else | |
#endif | |
_enable_interrupts(); // let the timers do their work | |
} | |
/* | |
* comment minifloat: loop() removed | |
* main - application main program | |
* loop runs in waitcmd() | |
*/ | |
int main(void) { | |
setup(); | |
init910(); | |
waitcmd(); //has intrinsic loop | |
return (0); //never reached | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Name: Makefile | |
# Author: minifloat | |
# This file was made from a prototype Makefile. | |
# Modify it according to your needs. | |
# You should at least check the settings for | |
# MCU ........ defines the MCU you're using | |
# OBJECTS .... is your object list; | |
# for each *.c file a *.o entry exists | |
# DBGDEVICE .. specifies the driver for mspdebug | |
MCU = msp430g2231 | |
OBJECTS = main.o timera_serial.o 910.o | |
DBGDEVICE = rf2500 | |
# Tune the lines below only if you know what you're doing | |
COMPILE = msp430-gcc -Os -Wall -g -mmcu=$(MCU) -fdata-sections -ffunction-sections | |
all: $(OBJECTS) | |
$(COMPILE) -o main.elf $(OBJECTS) -Wl,--gc-sections -Wl,-Map=main.map | |
msp430-objdump -S main.elf >main.lst | |
# msp430-nm main.elf | |
msp430-size main.elf | |
%.o: %.c | |
$(COMPILE) -c $< | |
.PHONY: clean | |
clean: | |
rm -fr main.elf $(OBJECTS) main.lst main.map | |
.PHONY: flash | |
flash: all | |
mspdebug $(DBGDEVICE) "erase" | |
mspdebug $(DBGDEVICE) "prog main.elf" | |
# For debugging, these four steps ar needed: | |
# 1. open two terminal windows | |
# 2. navigate to the project's folder | |
# 3. in the first window, type "make debug" and wait until | |
# mspdebug states "waiting for connection on port 2000..." | |
# 4. in the second window, type "make gdb" and beat the hell | |
# out of your code (omg) | |
# 5. after terminating the debug session, tell me how | |
# i can automate this (also omg) | |
.PHONY: debug | |
debug: all | |
mspdebug $(DBGDEVICE) "gdb" & | |
.PHONY: gdb | |
gdb: | |
msp430-gdb --symbols=main.elf --eval-command=target\ remote\ localhost:2000 | |
#EOF |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//------------------------------------------------------------------------ | |
// serial.h - function declarations for simple blocking serial routines | |
//------------------------------------------------------------------------ | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
#define CALIBRATED 0 | |
#if CALIBRATED | |
#define F_CPU 1000000 // DCO speed | |
#else | |
#define F_CPU 16025000 // DCO speed | |
#endif | |
#define BAUD_RATE 9600 // serial port speed | |
static const int VER = 0x0100; | |
void init_serial(const unsigned duration) __attribute__((always_inline)); | |
int getchar(void) __attribute__((always_inline)); | |
int putchar(const int) __attribute__((always_inline)); | |
#ifdef __cplusplus | |
} /* extern "C" */ | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* timera_serial.c - TIMERA implementations of init_serial(), getchar(), putchar() | |
* | |
* Created on: Oct 30, 2011 | |
* Author: kimballr - rick@kimballsoftware.com | |
* | |
* Desc: This code uses TimerA CCR0 and CCR1 to implement blocking serial | |
* send and receive functionality using interrupt helper routines. | |
*/ | |
#include <msp430.h> | |
#include <stdint.h> | |
#include "serial.h" | |
/** | |
* tuart_config_t - configuration and runtime variables | |
*/ | |
typedef struct { | |
const uint16_t TICKS_PER_BIT; // timer clock ticks per bit | |
const uint16_t TICKS_PER_BIT_DIV2; // timer clock ticks per half bit | |
volatile int16_t UARTRXBUF; // RX buffer, only valid after a received character | |
volatile int16_t UARTTXBUF; // TX buffer used to xmit character | |
volatile uint16_t RXFLAG; // flag to indicate we have data ready=0x01, data not ready=0x00 | |
} tuart_config_t; | |
static tuart_config_t uart_config = { | |
.TICKS_PER_BIT = (F_CPU/BAUD_RATE), | |
.TICKS_PER_BIT_DIV2 = (F_CPU/BAUD_RATE/2), | |
.UARTRXBUF=0, | |
.UARTTXBUF=0, | |
.RXFLAG=0 | |
}; | |
/** | |
* init_serial(const unsigned bitduration) | |
* | |
* Really simple use of the TimerA hardware so we can have an | |
* API that is compatible with a simple software only version. | |
* We setup the TimerA CC0/CC1 using the default RX/TX pins | |
* for the launchpad and bitduration (F_CPU/BAUD_RATE). | |
* | |
* Note: This code use interrupts and needs the global interrupt flag enabled. | |
* However, this code doesn't modify the global interrupt flag. | |
* | |
*/ | |
void init_serial(const unsigned bitduration) { | |
P1OUT |= BIT1; // Set output pin high (idle state) | |
P1SEL |= BIT1 | BIT2; // enable TA0.CCI0A & TA0.CCI1A | |
P1DIR &= ~BIT2; // rxPin input, | |
P1DIR |= BIT1; // txPin output | |
TA0CCTL0 = OUT; // OUTPUT | |
TA0CCTL1 = SCS | CM1 | CAP | CCIE; // INPUT SYNC/ CM1 / CAPTURE/ interrupt enabled | |
TA0CTL = TASSEL_2 | MC_2 | TACLR; // use SMCLK, in continuous UP mode, clear TACLR, | |
} | |
/** | |
* int getchar() - blocking read char from serial port | |
* | |
* TBD: we could really go to sleep and wait for Timer interrupt | |
* to wake us up when it is ready to do something. | |
* | |
*/ | |
int getchar(void) { | |
// sit and spin waiting for an incoming character | |
while (!(uart_config.RXFLAG)) { | |
; // busywait on our volatile RX completion flag, set high when character available | |
} | |
uart_config.RXFLAG = 0; // reset to low | |
return uart_config.UARTRXBUF; // return RXed character | |
} | |
/** | |
* putchar(const int c) - write byte to serial port | |
* | |
* Desc: Use the TIMERA ISR to xmit a single character. Offloads | |
* the CPU and lets the timer do the work. | |
* | |
*/ | |
int putchar(const int c) { | |
// When a transmit is in process the TIMERA interrupt flag | |
// will be set. The ISR disables the interrupt | |
// flag when it has sent the final stop bit. | |
while (TACCTL0 & CCIE) { | |
; // wait for previous XMIT to finish | |
} | |
// make the next output at least TICKS_PER_BIT in the future | |
// so we don't stomp on the the stop bit from our previous xmt | |
TACCR0 = TAR; // resync with current TimerA clock | |
TACCR0 += uart_config.TICKS_PER_BIT; // setup the next timer tick | |
TACCTL0 = OUTMOD0 | CCIE; // re-enable interrupts and use OUT bit | |
// now that we have set the next interrupt in motion | |
// we quickly need to set the TX data. Hopefully the | |
// next 2 lines happens before the next timer tick. | |
// Note: This code makes great use of the msp430 peripherals | |
// | |
// In the code above, we start with a busy wait on the CCIE | |
// interrupt flag. As soon as it is available, we setup the next | |
// send time and then re-enable the interrupt. Until that time happens, | |
// we have a few free cycles available to stuff the start and stop bits | |
// into the data buffer before the timer ISR kicks in and handles | |
// the event. Note: if you are using a really slow clock or a really | |
// fast baud rate you could run into problems if the interrupt is | |
// triggered before you have finished with the USARTTXBUF | |
uart_config.UARTTXBUF = c; // load our pseudo register used by the TIMERA0_VECTOR | |
uart_config.UARTTXBUF |= 0x100; // Add the stop bit '1' | |
uart_config.UARTTXBUF <<= 1; // Add the start bit '0' | |
return 0; | |
} | |
/** | |
* TIMER0_A1_RX_ISR - Receive Interrupt Handler | |
* | |
* This ISR works in two modes. It starts out in capture mode | |
* waiting for the RX line to go from HI to LO indicating a | |
* start bit from the sender. It then switches to | |
* compare mode. Each tick, it sets a future time to wake up and | |
* sample the RX line. The sample is done by calculating | |
* the time for the center of the data bit for the given | |
* baud rate and waking up and taking a sample at that time. | |
* Once the stop bit is received it goes back into | |
* capture mode waiting for the next start bit. | |
* | |
* Note: serial data is LSB first | |
* | |
*/ | |
#ifdef __MSP430_HAS_TA3__ | |
#define TAIV_TACCR1 TA0IV_TACCR1 | |
#endif | |
__attribute__((interrupt(TIMER0_A1_VECTOR))) | |
void TIMER0_A1_VECTOR_RX_ISR(void) { | |
static uint8_t rxBitCnt = 8; // | |
static uint8_t rxData = 0; // recv buffer, so we don't stomp on the external character buffer | |
// reading TAIV clears the interrupt | |
if ( TAIV == TAIV_TACCR1 ) { | |
TA0CCR1 += uart_config.TICKS_PER_BIT; // Setup next time to sample | |
if (TA0CCTL1 & CAP) { // Is this the start bit? | |
TA0CCTL1 &= ~CAP; // Switch capture to compare mode | |
TA0CCR1 += uart_config.TICKS_PER_BIT_DIV2; // Sample from the middle of D0 | |
} | |
else { | |
rxData >>= 1; // next bit, shift in a zero | |
if (TA0CCTL1 & SCCI) { // get bit waiting in receive latch | |
rxData |= 0x80; // if latch set, then set buffer high bit to 1 | |
} | |
if ( !(--rxBitCnt) ) { // All bits RXed? | |
uart_config.UARTRXBUF = rxData; // Store in users recv buffer | |
rxBitCnt = 8; // Re-load bit counter | |
TA0CCTL1 |= CAP; // Switch compare to capture mode | |
uart_config.RXFLAG = 1; // trigger the received flag | |
} | |
} | |
} | |
} | |
/** | |
* TIMER0_A0_TX_ISR - TX Interrupt Handler | |
* | |
* Handle the sending of a data byte with one | |
* start bit + 8 data bits + stop bit. | |
* | |
* Note: We don't need to clear any interrupt flags here | |
* this isn't a vectored interrupt, only one event | |
* will get us here. | |
* | |
*/ | |
__attribute__((interrupt(TIMER0_A0_VECTOR))) | |
void TIMER0_A0_TX_ISR(void) { | |
static uint8_t txBitCnt = 10; // 1 Start bit + 8 data bits + 1 stop bit | |
/** | |
* ready the value of the OUT bit which will be set when the TAR == TACCR0 | |
*/ | |
TACCTL0 |= OUTMOD2; // reset OUT (set to 0) OUTMOD2|OUTMOD0 (0b101) | |
if (uart_config.UARTTXBUF & 0x01) { // look at LSB if 1 then set OUT high | |
TACCTL0 &= ~OUTMOD2; // set OUT (set to 1) OUTMOD0 (0b001) | |
} | |
uart_config.UARTTXBUF >>= 1; // shift in the next bit for the next time through | |
if ( --txBitCnt == 0 ) { // all bits transmitted ? | |
TACCTL0 &= ~CCIE; // disable interrupt | |
txBitCnt = 10; // Re-load bit counter | |
} | |
TACCR0+=uart_config.TICKS_PER_BIT; // setup next time to send a bit, OUT will be set then | |
} |
Hi, i need same help. i tried to cmpile this code in CCS 5 for the msp430g2553 but it gets same error. What program did you use to compile??
same errors are 1) #115 function "usdelay" was referenced but not defined
2) Multiple markers at this line
- #71-D incomplete type is not
allowed
- #66 expected a ";"
3)Multiple markers at this line
- #249 function "attribute" has already been defined
- #80 expected a type specifier
- #142 unnamed prototyped parameters not allowed when body is
present
it is posible that new ccs is not compatible at all.. i guess
my email danielgbat89@gmail.com
pd: sorry about my english!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a modified version of the AVR910 ISP programmer from http://www.mikrocontroller.net/articles/Launchprog. This code is written to be able to run on the msp430g2211, however it will run on other chips with a TimerA peripheral.
The big modification in this version is that it has blocking TimerA serial routines that are much smaller than the previous async ringbuffer enabled version. Also, this version will run without an XTAL soldered in. See main.c comments for all the changes. Compiled flash size is about 1800 bytes and it uses a very small amount of ram.
From the command line you do something like this:
$ avrdude -c avr910 -P /dev/ttyACM0 -b 9600 -v -p m1284p -U flash:w:cyclon1284p.hex:a
-rick