Initial commit of tweaked ATtiny88 code

Only some minor cleanup performed. Builds fine with AS7 but is otherwise untested.
This commit is contained in:
true 2023-02-11 04:47:30 -08:00
commit 08102c2bcd
15 changed files with 1672 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
attiny88_main/Debug
attiny88_main/Release

Binary file not shown.

View File

@ -0,0 +1,141 @@
:100000002DC047C046C045C044C043C042C041C0E7
:1000100040C03FC03EC03DC0AAC33BC03AC039C08B
:100020008BC037C036C034C3BDC1C0C1CAC1DBC17B
:10003000F8C116C228C227C2F9C103C224C223C212
:1000400022C221C220C209C20BC20AC21CC21BC2E8
:100050001AC219C218C217C216C207C211241FBE83
:10006000CFEFD2E0DEBFCDBF11E0A0E0B1E0E8EA23
:10007000F8E002C005900D92A430B107D9F721E055
:10008000A4E0B1E001C01D92A433B207E1F76DD244
:1000900009C4B6CFE4E6F0E080818E7F8083EAE792
:1000A000F0E08FED8083ACE7B0E08C918F7D8C9396
:1000B0008081886880830895282F803188F490910A
:1000C0007C00907F982B90937C00883030F481E006
:1000D00001C0880F2A95EAF701C080E080937E0076
:1000E000613021F480917C00806405C0623029F485
:1000F00080917C008F7B80937C00089590917A00A2
:10010000292F207496FD15C080930C01662311F0F1
:10011000982F01C090E09093040190917C009F7013
:10012000906890931F0190917A00906490937A0068
:1001300001C021E0822F08951F920F920FB60F92F7
:1001400011242F934F935F938F939F93AF93BF93FC
:10015000EF93FF93E0917C00EF7020910401222344
:10016000D1F080910C012817B1F0E930A0F4AE2F46
:10017000B0E0AA0FBB1FA35FBE4F4D915C911197DA
:100180008091780090917900840F951F96958795BE
:1001900011969C938E9380910C01882359F0809145
:1001A0000C01815080930C0180917A0080648093CF
:1001B0007A0011C021110DC0E93058F4F0E08091AF
:1001C000780090917900EE0FFF1FE35FFE4F91835F
:1001D000808310921F01FF91EF91BF91AF919F918A
:1001E0008F915F914F912F910F900FBE0F901F90A5
:1001F00018958AB1806F8AB987B18F6087B98BB142
:10020000806F8BB988B18F6088B90895CF93DF93E1
:100210008BB1806F8BB988B18F6088B9C8E8D0E0A6
:100220008EEF8883AAE8B0E08C938AEF90E09093F9
:100230008500809384003BB124E02D0D81E090E0A7
:10024000AC0101C0440F2A95EAF7242F20952323FF
:100250002BB928B10D2C01C0880F0A94EAF78095BC
:10026000822388B9ED2DF0E0EB5DFE4F8BEF90819E
:10027000282F291B2883ED2DF0E0EF5DFE4F9081A4
:10028000891B8C93DF91CF9108959BB1906F9BB99F
:10029000E0E8F0E090819F70908397B1907F97B9EC
:1002A00095B7906195BF47B121E030E0B90102C038
:1002B000660F771F8A95E2F7CB01462B47B998B1B5
:1002C000907F98B92A9A98B1982B98B92A9878E093
:1002D0007A95F1F797B18095982397B998B18923CA
:1002E00088B985B78F7E85BF0895843038F466233A
:1002F00029F0E82FF0E0E050FF4F6083089583700D
:1003000080930501089580910501E82FF0E0E05009
:10031000FF4F9081911101C091E02E2DE11003C09B
:1003200061E08FE012C0213019F460E080E018C075
:10033000223061F490911F01992319F0EE24E39487
:100340000895A3DF6FEF80910501B6CE4E2D50E0EA
:10035000892F90E002964817590719F461E083E06D
:10036000CDCE8417950794F42150E22E80911F0181
:1003700081110CC06FEF8FE09FDE3BDF8EEF80932B
:10038000800084B1866084B91092200108958F2D79
:100390004F2D50E04A31510508F075C0FA01EC5E6E
:1003A000FF4F0994F12C10922A0108958091330196
:1003B000882309F46CC0F090300183E0809333010E
:1003C00050C0E0912F01E43020F4F0E0EB5DFE4FEF
:1003D00006C0E83008F044C0F0E0E35EFE4F8091D4
:1003E000300180833DC080913301882309F44FC0E0
:1003F00080911D0190911E01892B09F444C06091E8
:100400001D0170911E0180913001681B710987FDEB
:10041000739570930701609306018EE390E024D2F8
:100420001FC0809133018230D8F41DC0809120011B
:10043000811117C010922001E12C88E080932001E7
:1004400010C08091200181110CC010922001E12C7C
:1004500080912F0154DF81E0F1CF84E08093090186
:10046000F12C10922A0180E00895809133018823B5
:1004700071F080912F01843098F7609130016623EC
:1004800079F333DFEDCFF12C10922A0181E008954A
:100490008093BB00ECEBF0E08081806880838081FA
:1004A0008F7B808380E008958F2D8830B9F089306C
:1004B000C1F0843051F580912F01803428F490E010
:1004C000C8D1E6DF81E006C08091BC008F7B8093BD
:1004D000BC008FEFF12C10922A0108958091080141
:1004E0000EC0E0912F01E370F0E0EE0FFF1FE35F1D
:1004F000FE4F808191819695879596958795C8DF67
:10050000F12C10922A0181E008958091BC008F7B2C
:100510008093BC008FEF089580911D0190911E0182
:1005200090910601891B982F959595959595891B16
:1005300008958E2DE11003C062E088E0BDCD8330C8
:1005400019F461E084E0DACD843070F08150E82E57
:1005500080911F01811108C061E08FE0ADDD109234
:100560002001DADF80930801089580E8809361001C
:100570001092610082B3806F82BB1DB881E084B9A4
:1005800017B81AB8CFEFCEB9DEEFD5B9C8B9CBB925
:1005900030DE22E02093B8008CEF8093B90086EE25
:1005A0008093BA001092BD0085E48093BC008091D6
:1005B00064008A7F809364009BEF95BD8DE387BDC7
:1005C00016BC20936E00809164008C7F8093640041
:1005D000C0938900C0938800C0938A001092850060
:1005E00010928400D093800089E180938100109262
:1005F000820080918000809329019093860084B1CD
:10060000866084B910926F0045DD629923C042DD97
:100610002FEF80E792E0215080409040E1F700C04A
:100620000000629917C0789488E08093200181DFF0
:1006300080911F018111FCCF60911D0170911E01FD
:1006400070930701609306018EE390E00DD1109244
:1006500020010DC08EE390E003D1813322E09207A8
:1006600014F081E191E0909307018093060183B734
:10067000897F90910901892B83BF10920901789499
:1006800083B7816083BF889583B78E7F83BFEFCFA9
:100690001F920F920FB60F9211242F933F934F93F7
:1006A0005F936F937F938F939F93AF93BF93EF93DA
:1006B000FF938091B900887F803AF1F160F4883629
:1006C00009F43FC028F4882391F18036D1F134C079
:1006D000803839F031C0883B41F170F5883A29F112
:1006E0002BC08091BB00F1100FC0982F92959F7086
:1006F000F92E982F9F7090932F0110923301109232
:100700002A0187FF1EC00AC0E0913301EF5FE3704A
:10071000E0933301F0E0E15DFE4F808338DE882313
:1007200081F08091BC008F7B0AC0BEDE0AC0809140
:10073000BC0080698093BC008091BC008064809381
:10074000BC008091BC0080688093BC00FF91EF9159
:10075000BF91AF919F918F917F916F915F914F91D9
:100760003F912F910F900FBE0F901F9018951F92E1
:100770000F920FB60F9211242F933F934F935F93D5
:100780006F937F938F939F93AF93BF93EF93FF9359
:1007900080910B018F5F883C18F480930B010CC093
:1007A00010920B0180910A018F5F843618F48093B8
:1007B0000A0102C010920A0187B58D3311F08DE352
:1007C00001C08EE387BD80912001882371F0809164
:1007D0002001813021F0883019F4ABDE01C093DDB7
:1007E0008E2D8F3F11F08F5FE82E80912001813098
:1007F00041F081E08D0D833010F4D82E01C0D12C52
:1008000005DDFF20A1F080912A018F5F80932A01EE
:10081000823368F0F12C10922A018091BC008F7B0A
:100820008093BC008091BC0080648093BC0086B53E
:10083000FF91EF91BF91AF919F918F917F916F91B8
:100840005F914F913F912F910F900FBE0F901F908E
:100850001895F999FECF81BDF89A992780B508952A
:10086000A8E1B0E042E005C010D0272F0FC0DC01A6
:10087000862FE82FF999FECF05C0E1BDF89AE395E0
:1008800000B40D924150C8F70895262FF999FECF74
:100890001FBA81BD20BD0FB6F894FA9AF99A0FBE1F
:0808A00001960895F894FFCFC2
:0408A8000101010148
:00000001FF

107
attiny88_main/src/adc.c Normal file
View File

@ -0,0 +1,107 @@
/*
* adc.c
*
* Created: 6/9/2014 11:07:35 PM
* Author: true
*/
#include "adc.h"
#include <avr/interrupt.h>
volatile uint8_t adc_busy;
volatile uint8_t adc_reread;
volatile uint16_t adc_result[ADC_MAX_FEEDBACK + 1];
static uint8_t adc_averages;
volatile uint8_t adc_read_mode;
/* functions */
void adc_init()
{
// make sure ADC power is enabled
PRR &= ~_BV(PRADC);
// clear all settings; set the ADC prescaler bits to get 500KHz ADC clock (SYSCLK/16), disable auto trigger
ADCSRA = _BV(ADPS2) | _BV(ADPS0) | ~(_BV(ADATE));
// set to right-aligned mode
ADMUX &= ~(_BV(ADLAR));
// enable the ADC, enable interrupts
ADCSRA |= _BV(ADEN) | _BV(ADIE);
}
void adc_channel(uint8_t channel, uint8_t vref)
{
// can we set channel?
if (channel < ADC_CHAN_INVALID) {
// set MUX[3:0] to the specified channel
ADMUX = (ADMUX & 0xf0) | (channel & 0x0f);
// also, if this is an actual pin, disable digital input on this pin
DIDR0 = (channel < 8) ? _BV(channel) : 0;
}
// set the voltage source
if (vref == ADC_REF_AVCC) {
ADMUX |= (_BV(REFS0));
} else if (vref == ADC_REF_BANDGAP) {
ADMUX &= ~(_BV(REFS0));
}
}
uint8_t adc_start(uint8_t reread, uint8_t enable_averaging)
{
// is a conversion already running?
if (ADCSRA & _BV(ADSC)) {
return 1;
}
// set up amount of times to re-read, and mark the amount of values to average
adc_reread = reread;
adc_averages = enable_averaging ? reread : 0;
// start conversion
adc_busy = 0x80 | (ADMUX & 0x0f);
ADCSRA |= _BV(ADSC);
return 0;
}
/* ISR */
ISR(ADC_vect)
{
uint8_t channel;
channel = ADMUX & 0x0f;
// mark our result in the average table
if (adc_averages) {
// except for the first read
if (adc_averages != adc_reread) {
// we do successive averaging; it's faster, smaller code, less RAM, and good enough for our purpose
// update our feedback
if (channel <= ADC_MAX_FEEDBACK) {
adc_result[channel] = (adc_result[channel] + ADC) >> 1;
}
}
}
if (adc_reread) {
adc_reread--;
// start another conversion
ADCSRA |= _BV(ADSC);
} else {
// determine if we need to update feedback
if (!adc_averages && channel <= ADC_MAX_FEEDBACK) {
// not averaging, so just store last result
adc_result[channel] = ADC;
}
adc_busy = 0;
}
}

56
attiny88_main/src/adc.h Normal file
View File

@ -0,0 +1,56 @@
/*
* adc.h
*
* Created: 6/9/2014 11:07:51 PM
* Author: true
*/
#ifndef ADC_H_
#define ADC_H_
#include "config.h"
#define ADC_CHAN_0 0
#define ADC_CHAN_1 1
#define ADC_CHAN_2 2
#define ADC_CHAN_3 3
#define ADC_CHAN_4 4
#define ADC_CHAN_5 5
#define ADC_CHAN_6 6
#define ADC_CHAN_7 7
#define ADC_CHAN_TEMP 8
#define ADC_CHAN_BANDGAP 14
#define ADC_CHAN_GND 15
#define ADC_CHAN_INVALID ADC_CHAN_GND + 1 // one above last valid channel
#define ADC_REF_AVCC 1
#define ADC_REF_BANDGAP 2
#define ADC_REF_NO_SET 255
#define ADC_MAX_FEEDBACK ADC_CHAN_TEMP
// adc read interrupt
extern volatile uint8_t adc_busy;
extern volatile uint16_t adc_result[ADC_MAX_FEEDBACK + 1];
// main timer adc handler
extern volatile uint8_t adc_read_mode;
register uint8_t adc_read_step asm("r14");
/* application specific */
#define ADC_READ_LED_RED ADC_CHAN_0
#define ADC_READ_LED_GREEN ADC_CHAN_1
#define ADC_READ_LED_BLUE ADC_CHAN_2
/* prototypes */
void adc_init();
void adc_channel(uint8_t channel, uint8_t bandgap_ref);
uint8_t adc_start(uint8_t reread, uint8_t enable_averaging);
#endif /* ADC_H_ */

View File

@ -0,0 +1,34 @@
/*
* config.h
*
* Created: 5/24/2014 9:22:14 AM
* Author: true
*/
#ifndef CONFIG_H_
#define CONFIG_H_
#include <stdint.h>
#include <avr/io.h>
#include <avr/sfr_defs.h>
// system
#define F_CPU 8000000UL
// LEDs
#define LED_COMMON_ANODE // defined = common anode, undef = common cathode
//#define LED_RGBX_4LED 1 // defined = use 4 LEDs (RGBX), undef = use 3 LEDs (RGB)
// i2c config
#define I2C_SLAVE_ADDRESS 0x73 // 7-bit address (0b1110011)
#define I2C_ENABLE_ADDR_ZERO 0 // 1 = enable response on 0x00, 0 = disable
#endif /* CONFIG_H_ */

60
attiny88_main/src/i2c.h Normal file
View File

@ -0,0 +1,60 @@
/*
* i2c.h
*
* Created: 5/21/2014 11:41:32 PM
* Author: true
*/
#ifndef I2C_H_
#define I2C_H_
#include "config.h"
/* macros */
#define i2c_clear_int_flag() TWCR |= _BV(TWINT)
#define i2c_disable_interrupt() TWCR &= ~(_BV(TWIE))
#define i2c_enable_interrupt() TWCR |= _BV(TWIE)
#define i2c_disable_slave() TWCR &= ~(_BV(TWEA))
#define i2c_enable_slave() TWCR |= _BV(TWEA)
/* configuration */
static inline void i2c_slave_init(uint8_t address, uint8_t enable_general_addr)
{
// set bitrate register, clear prescaler
// should get us 400KHz (fast mode) max rate
TWBR = 2;
TWSR = ~(_BV(TWPS0) | _BV(TWPS1));
// set slave address and clear address mask
TWAR = ((address << 1) | (enable_general_addr & 1));
TWAMR = 0;
// enable auto-ack, enable TWI, and enable the TWI interrupt
TWCR = _BV(TWEA) | _BV(TWEN) | _BV(TWIE);
}
/* sending */
static uint8_t i2c_slave_tx(uint8_t byte, uint8_t is_last_byte)
{
// load data
TWDR = byte;
// start sending
TWCR |= _BV(TWINT);
if (is_last_byte) {
// this is all the data we have to send; send a nack after this byte
i2c_disable_slave();
}
return 0;
}
#endif /* I2C_H_ */

View File

@ -0,0 +1,102 @@
/*
* i2c_interrupt.h
*
* Created: 6/13/2014 1:53:36 AM
* Author: true
*/
#ifndef I2C_INTERRUPT_H_
#define I2C_INTERRUPT_H_
#include "config.h"
ISR(TWI_vect)
{
// i2c is low priority - allow it to be interrupted
// sei();
// figure out wtf to do
switch (TWSR & 0xf8) { // TWI state
// ** SLAVE RECEIVE ** //
case 0x60: // slave addr+write receive to valid address
case 0x68: { // slave addr+write arbitration lost?
// nothing to do. we're ready to receive.
break;
}
/*
case 0x70:
case 0x78: {
// unused: this is for genaddr mode.
}
*/
case 0x80: { // slave data receive w/ACK returned
if (pegleg_data_rx(TWDR)) {
// I wanted to send a NAK, but TWI already sent an ACK. oh fucking well.
// send NACK if any further packets are received
i2c_disable_slave();
}
break;
}
/*case 0x90: { // slave genaddr data receive w/ACK returned
// not using this
}*/
case 0x88: // slave data receive w/NACK returned, no longer addressed
//case 0x98: // slave genaddr data receive w/NACK returned, no longer addressed
case 0xa0: { // STOP asserted; done receiving? no longer addressed
// we can re-enable the slave...
i2c_enable_slave();
break;
}
// ** SLAVE TRANSMIT ** //
case 0xa8: { // slave read request to valid address
// try to send data
pegleg_data_tx();
break;
}
case 0xb8: { // slave read continues, master ACK'd last packet
// do we have a mode in progress?
// NOTE: by default, slave tx modes won't unset, but slave mode will be disabled
// when the last packet is sent, and re-enabled on the following ACK/NACK.
pegleg_data_tx();
break;
}
case 0xb0: // arbitration lost
// I don't even know how the fuck this happened
case 0xc0: // slave read ends, master doesn't want more data
// this usually happens after we've sent data and master doesn't want any more.
// if we had more data, tough shit, master doesn't want it. so we don't send it.
case 0xc8: { // slave read ends, master wants more data though
// this usually happens after we're done sending, but master is requesting more.
// but slave mode is disabled, so don't send anything.
// we need to make sure send mode is disabled, and we need to re-enable slave mode.
i2c_enable_slave();
break;
}
// ** ERROR AND UNHANDLED ** //
case 0x00: { // bus error
// set TWSTO, clear TWINT (by setting) as per datasheet
TWCR |= (_BV(TWSTO)) | (_BV(TWINT));
// and make sure slave is enabled
i2c_enable_slave();
break;
}
default: {
// something unhandled? fuck it, we want to be a slave.
// reset everything and start over.
i2c_enable_slave();
}
}
// done with this TWI bit
i2c_clear_int_flag();
}
#endif /* MAIN_INTERRUPT_H_ */

164
attiny88_main/src/led.c Normal file
View File

@ -0,0 +1,164 @@
/*
* led.c
*
* Created: 6/13/2014 1:44:28 AM
* Author: true
*/
#include "led.h"
/* led */
uint8_t rgbled_pwm_lf[4]; // pwm value for TIMER1 OCA LED outputs
uint8_t rgbled_pwm_rt[4]; // pwm value for TIMER1 OCB LED outputs
static uint8_t rgbled_read_sel; // LED light sensor select
static uint8_t rgbled_sensitivity[4] = {1, 1, 1, 1};
/* adc */
volatile uint8_t adc_busy;
volatile uint16_t adc_result[ADC_MAX_FEEDBACK + 1];
volatile uint8_t adc_read_mode;
/* functions */
// sets up the IO pins for LED output function.
void rgbled_io_init()
{
// PortD[4:7] (left) and PortC[0:3] (right) are LEDs
// Also, Right LEDs are capable of ADC input on ALL pins (ADC[0:3])
// set all pins as outputs
DDRD |= 0xf0;
DDRC |= 0x0f;
#ifdef LED_COMMON_ANODE
// com-anode: pin is high to disable
PORTD |= 0xf0;
PORTC |= 0x0f;
#else
// com-cathode: pin is low to disable
PORTD &= 0x0f;
PORTC &= 0xf0;
#endif
}
// sets the appropriate pins and PWM values for the LED index specified in rgbled_idx.
// note: this index is updated externally, and not by this function.
void rgbled_update()
{
// clear all selected LED pins
// we have to clear the select line then set it because we can't fully disable the PWM for some reason
#ifdef LED_COMMON_ANODE
// make sure all pins are high
PORTD |= 0xf0;
PORTC |= 0x0f;
#else
// make sure all pins are low
PORTD &= 0x0f;
PORTC &= 0xf0;
#endif
// set pwm OCx registers to max
timer1_set_oca(TIMER1_COMPARE);
timer1_set_ocb(TIMER1_COMPARE);
// and set pwm counter value to 1 before expiry
timer1_set(TIMER1_COMPARE - 1);
// now we set the desired LED
// turn on one LED in each group
#ifdef LED_COMMON_ANODE
// make sure active pin is output low and others are high
PORTD &= ~(_BV(rgbled_idx + 4));
PORTC &= ~(_BV(rgbled_idx));
#else
// make sure active pin is output high and others are low
PORTD |= _BV(rgbled_idx) << 4;
PORTC |= _BV(rgbled_idx);
#endif
// load new pwm OCx values for this LED
timer1_set_oca(rgbled_pwm_lf[rgbled_idx]);
timer1_set_ocb(rgbled_pwm_rt[rgbled_idx]);
}
// sets up the PortC LED matrix as a diode light sensor.
// configures the specified LED on the ADC.
// this function assumes common anode.
void rgbled_sensor_init(uint8_t led)
{
// set the left eye high (fixes color flash/tearing)
PORTD |= 0xf0;
// disable both eye's PWM (required for right eye, fixes color flash/tearing in left eye)
TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(COM1B0));
// ground the LED
DDRC &= 0xf0; // set all LEDs cathode as inputs
MCUCR |= (_BV(PUD)); // globally disable pullups
DDRC |= (_BV(led)); // set our LED as an output
PORTC = (PORTC & 0xf0); // set all LEDs cathode low
PORTB |= (_BV(PORTB2)); // set anode high
// reverse LED bias
PORTC |= (_BV(led)); // set cathode high
PORTB &= ~(_BV(PORTB2)); // set anode low
_delay_us(3); // allow it to charge fully
// set LED as input
DDRC &= ~(_BV(led)); // set led cathode as input
PORTC &= ~(_BV(led)); // set led cathode pullup off
MCUCR &= ~(_BV(PUD)); // re-enable global pullups
}
// starts ADC to read the value of charge remaining on the LED
void rgbled_sensor_sensitivity(uint8_t ledidx, uint8_t sensitivity)
{
if (ledidx <= 0x03) {
if (sensitivity) {
rgbled_sensitivity[ledidx] = sensitivity;
}
}
}
void rgbled_sensor_read_idx(uint8_t ledidx)
{
rgbled_read_sel = ledidx & 0x03;
}
void rgbled_sensor_read()
{
uint8_t sens;
sens = rgbled_sensitivity[rgbled_read_sel];
if (!sens) sens = 1;
if (adc_read_step == 0) {
// adc_init();
// clear ADC bias by reading ground
adc_channel(ADC_CHAN_GND, ADC_REF_AVCC);
} else if (adc_read_step == 1) {
adc_start(0, 0);
} else if (adc_read_step == 2) {
// if the ADC is done, charge up LED for reading
if (adc_busy) {
adc_read_step--;
} else {
rgbled_sensor_init(rgbled_read_sel);
adc_channel(rgbled_read_sel, ADC_REF_NO_SET);
}
} else if (adc_read_step == (2 + sens)) {
// if vref has changed, it should be stable by now; start reading LED value
adc_start(3, 1);
} else if (adc_read_step > (2 + sens)) {
adc_read_step--;
if (!adc_busy) {
// we are done! :) finish up...
adc_channel(ADC_CHAN_GND, ADC_REF_NO_SET); // change ADC to not look at a real pin
rgbled_io_init(); // set LED pins up again
timer1_pwm_reinit(); // and set up PWM again
adc_read_mode = 0; // clear ADC read mode
}
}
}

44
attiny88_main/src/led.h Normal file
View File

@ -0,0 +1,44 @@
/*
* led.h
*
* Created: 6/13/2014 1:40:53 AM
* Author: true
*/
#ifndef LED_H_
#define LED_H_
/* incl */
#include "config.h"
#include <util/delay.h>
#include "adc.h"
#include "timer.h"
/* led */
#define LED_RED 0
#define LED_GREEN 1
#define LED_BLUE 2
#define LED_SPARE 3
/* globals */
extern uint8_t rgbled_pwm_lf[4]; // pwm value for TIMER1 OCA LED outputs
extern uint8_t rgbled_pwm_rt[4]; // pwm value for TIMER1 OCB LED outputs
register uint8_t rgbled_idx asm("r13"); // the currently operated LED
/* prototypes */
void rgbled_io_init();
void rgbled_update();
void rgbled_sensor_sensitivity(uint8_t ledidx, uint8_t sensitivity);
void rgbled_sensor_read_idx(uint8_t ledidx);
void rgbled_sensor_read();
#endif /* LED_H_ */

574
attiny88_main/src/main.c Normal file
View File

@ -0,0 +1,574 @@
/*
* Whiskey Pirates Badge "PEGLEG CPU"
* Sub MCU Firmware for ATtiny88
*
* Created: 5/21/2014 9:24:48 PM
* Author: true
* ts:4
*
********
* PEGLEG CPU is responsible for:
* - aux gpio (todo: list specifically which GPIOs on the badge)
* - eye RGBLED matrix
* - temperature sensor
* - light sensor (using eye RGBLEDs; in practice uses the left eye red LED)
* - user config eeprom
*
********
* Use the following fuses for this project. Needs to run at 8MHz for 400khz I2C operation.
* 8MHz, self-program enabled (bootloader support), preserve EEPROM, BOD disabled, ISP enabled
* -U lfuse:w:0xEE:m -U hfuse:w:0xD7:m -U efuse:w:0x00:m
* (efuse will likely show as 0x06 after setting; this is fine, don't worry about it)
*
* Resources used: Mainline ISR 5% (3/63 timer counts simulated, as of some old rev)
* Flash 26.8%, SRAM 10.4% (as of the above rev)
*
**********
* Register Variables:
* main.c:comm_cmd:r15
* adc.h:adc_read_step:r14
* led.c:rgbled_idx:r13
*/
#include "config.h"
/* system */
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include "i2c.h"
#include "timer.h"
#include "adc.h"
#include "led.h"
/* modes (commands) */
#define MODE_NONE 0b0000
#define MODE_EXT_CMD 0b0001 // bit 4 unset = extra parameters needed, up to 6 commands
#define MODE_LED_SET_LEVEL 0b0010 // (0x00 reserved, 0x1? extra, leaving 0x2? through 0x7?)
#define MODE_TEMPSENSOR_CAL 0b0011
#define MODE_EEPROM_READ 0b0100
#define MODE_EEPROM_WRITE 0b0101
#define MODE_TEMPSENSOR_READ 0b1000 // bit 4 set = immediate, no extra parameters, process now
#define MODE_LIGHTSENSOR_READ 0b1001
#define MODE_SLEEP 0b1111
#define MODE_AUX_PIN_GET 0x10 // extended (send 0x10, cmd, data...)
#define MODE_AUX_PIN_SET 0x11 // ext commands MUST be 0x10 or higher! 0x00-0x0f are RESERVED!
#define MODE_LIGHTSENSOR_SENS 0x19
/* aux pin mode */
#define AUX_PIN_COUNT 10
#define AUX_PIN_OUTPUT 0x01 // sets to output if set, input if cleared
#define AUX_PIN_PORTSET 0x02 // output: sets high/low; input: sets pullup on/off
/* adc modes */
#define ADC_MODE_TEMPSENSOR 8
#define ADC_MODE_LIGHTSENSOR 1
/* prototypes */
static void system_init();
static void system_io_init();
static void tempsensor_cal();
/* globals */
static uint8_t tim0_milli;
static uint8_t tim0_centi;
static uint8_t tim0_profiler;
#define COMM_DATA_SIZE 4 // must be power of 2; default value is 4
register uint8_t comm_cmd asm("r15"); // currently processed SPI command
uint8_t comm_data_idx; // command data write index
uint8_t comm_data[COMM_DATA_SIZE]; // command data register
uint8_t comm_timeout; // command invalidate timeout
/* core */
static uint8_t pirate_sleep_mode = SLEEP_MODE_IDLE;
/* tempsensor */
static int8_t temperature;
static int16_t temp_offset;
/* eeprom */
#define EEPROM_ADDR_TEMPCAL 62 // 2 bytes
/* adc */
volatile uint8_t adc_busy;
volatile uint16_t adc_result[ADC_MAX_FEEDBACK + 1];
/* led */
uint8_t rgbled_pwm_lf[4]; // pwm value for TIMER1 OCA LED outputs
uint8_t rgbled_pwm_rt[4]; // pwm value for TIMER1 OCB LED outputs
uint8_t rgbled_light_level[4];
/* it begins */
int main(void)
{
// configure device and IO
system_init();
system_io_init();
// configure RGBLEDs
rgbled_io_init();
// configure i2c communications
i2c_slave_init(I2C_SLAVE_ADDRESS, I2C_ENABLE_ADDR_ZERO);
// configure system timer
timer0_init();
// configure led pwm timer
timer1_init();
// initialize adc
adc_init();
// try calibrating temperature sensor if needed
tempsensor_cal();
// and now we wait.
while (1) {
// set sleep mode, then set for idle sleep (CPU off, all peripherals on)
set_sleep_mode(pirate_sleep_mode);
pirate_sleep_mode = SLEEP_MODE_IDLE;
// re-enable interrupts and nap.
sei();
sleep_mode();
}
}
/* func */
static void system_init()
{
// make SURE we are running at 8MHz
// do this by first enabling clock divider setup mode,
CLKPR = _BV(CLKPCE);
// and disabling any divider
CLKPR = 0;
}
static void system_io_init()
{
// enable break-before-make outputs on all IO
PORTCR |= (_BV(BBMA) | _BV(BBMB) | _BV(BBMC) | _BV(BBMD));
// set ALL pins as inputs except PB0
DDRA = 0x00;
DDRB = 0x01;
DDRC = 0x00;
DDRD = 0x00;
// and enable pullups (this reduces power consumption)
// in the case of PB0, set it LOW
PORTA = 0xff;
PORTB = 0xfe;
PORTC = 0xff;
PORTD = 0xff;
}
/* temperature */
uint8_t tempsensor_process()
{
int8_t temp_gain;
int8_t temp_adj;
temp_adj = adc_result[ADC_CHAN_TEMP] - temp_offset; // our offset adjusted temperature
temp_gain = temp_adj >> 3; // our gain adjust amount
while (temp_gain > 0) {temp_gain--; temp_adj--;}; // correct positive gain
while (temp_gain < 0) {temp_gain++; temp_adj++;}; // correct negative gain
// save temperature
return temp_adj;
}
void tempsensor_read()
{
if (adc_read_step == 0) {
// select temperature channel
adc_channel(ADC_CHAN_TEMP, ADC_REF_BANDGAP);
} else if (adc_read_step == 3) {
// we've waited 1.5ms so the bandgap voltage should have been set.
// start conversion after bandgap ref change timeout per datasheet
adc_start(4, 1);
} else if (adc_read_step > 3) {
adc_read_step--;
if (!adc_busy) {
// revert reference to AVCC...per the datasheet only changes to
// bandgap should take ~1ms but changes back to AVCC seem to
// take a while to be accurate as well
adc_channel(ADC_CHAN_GND, ADC_REF_AVCC);
adc_read_mode = 0;
temperature = tempsensor_process();
}
}
}
void tempsensor_cal()
{
// NOTE: CALIBRATION IS SINGLE-POINT TO 0 DEGREES CENTIGRADE! ICE YOUR PEGLEG, MOTHERFUCKER!
// todo: figure out wtf I meant by this note in 2014 (this is me in 2023)
// looking at the code, it looks like a pin needs manually changed to calibrate.
// todo: add a zeroing offset calibration command to the command protocol?
// is pin PA2 low? (pin 3 on attiny88 - is pulled up - short to pin 5 / ground somewhere)
if ((PINA & _BV(PINA2)) == 0) {
// turn on the ADC, wait for it to warm up
adc_init();
_delay_ms(100); // todo: is this right? this seems slow
// is the pin still low? not a glitch?
if ((PINA & _BV(PINA2)) == 0) {
// enable interrupts
sei();
// start reading the temp sensor; stall until adc is done
adc_read_mode = ADC_MODE_TEMPSENSOR;
tempsensor_read();
while (adc_busy);
// here's our correction factor!
temp_offset = adc_result[ADC_CHAN_TEMP];
// write it to eeprom
eeprom_write_word((uint16_t *)EEPROM_ADDR_TEMPCAL, temp_offset);
// and that's it - we're done.
adc_read_mode = 0;
return;
}
}
// not saving a value - read the value from eeprom
temp_offset = eeprom_read_word((uint16_t *)EEPROM_ADDR_TEMPCAL);
// does it seem invalid?
if (temp_offset > 560) {
// yeah, this isn't right. load rough value for 0degC from datasheet.
// but you really should calibrate your chip, you lazy fuck.
temp_offset = 273;
}
}
/* comms */
static inline uint8_t pegleg_data_tx()
{
uint8_t ret;
switch (comm_cmd) {
case MODE_EEPROM_READ: {
if (comm_data[0] < 64) {
i2c_slave_tx(eeprom_read_byte((uint8_t *)(uint16_t)comm_data[0]), 1);
ret = 1;
} else {
// invalid address...
i2c_disable_slave();
ret = 255;
}
comm_cmd = 0;
comm_timeout = 0;
return ret;
}
case MODE_TEMPSENSOR_READ: {
i2c_slave_tx(temperature, 1);
comm_cmd = 0;
comm_timeout = 0;
return 1;
}
case MODE_LIGHTSENSOR_READ: {
i2c_slave_tx(adc_result[comm_data[0] & 0x03] >> 2, 1);
comm_cmd = 0;
comm_timeout = 0;
return 1;
}
default: {
// nothing active; invalid :(
i2c_disable_slave();
return 255;
}
}
return 0;
}
static uint8_t pegleg_cmd()
{
switch (comm_cmd) {
// no command: we just ACK this as we shouldn't ever get here
case MODE_NONE: {
comm_cmd = 0;
comm_timeout = 0;
break;
}
// standard commands
case MODE_EXT_CMD: { // used for more commands
if (comm_data_idx >= 1) {
comm_cmd = comm_data[1];
// set data index to last (will be reset on next data sent)
// and also reset timeout since this is effectively a new command
comm_data_idx = COMM_DATA_SIZE - 1;
comm_timeout = 0;
}
break;
}
case MODE_LED_SET_LEVEL: { // sets PWM rate for the 8 PWM LEDs
if (comm_data[0] < 4) {
rgbled_pwm_lf[comm_data[0]] = comm_data[1];
} else if (comm_data[0] < 8) {
rgbled_pwm_rt[comm_data[0] - 4] = comm_data[1];
}
comm_cmd = 0;
comm_timeout = 0;
break;
}
case MODE_TEMPSENSOR_CAL: {
// to use this function, make sure the temperature has been previously read.
// calculates the appropriate offset based on the reported temperature.
if (comm_data_idx >= 1) {
// update the offset
if (adc_result[ADC_CHAN_TEMP]) {
temp_offset = adc_result[ADC_CHAN_TEMP] - (int8_t)comm_data[1];
// write it to eeprom
eeprom_write_word((uint16_t *)EEPROM_ADDR_TEMPCAL, temp_offset);
// and that's it - we're done.
comm_cmd = 0;
comm_timeout = 0;
} else {
// no valid read performed; I fucking told you to do this!
comm_cmd = 0;
comm_timeout = 0;
return 1;
}
}
break;
}
case MODE_EEPROM_READ: {
// our data packet is already set; ready for read.
// but if the host keeps writing...
if (comm_data_idx > 1) {
comm_cmd = 0;
comm_timeout = 0;
}
break;
}
case MODE_EEPROM_WRITE: {
// TODO: implement
comm_cmd = 0;
comm_timeout = 0;
break;
}
// immediate commands
case MODE_TEMPSENSOR_READ: {
// attempt another read
if (!adc_read_mode) {
adc_read_mode = 0;
adc_read_step = 0;
adc_read_mode = ADC_MODE_TEMPSENSOR;
}
// now we are ready to read.
// data will probably be prior data unless the host waits. (need to verify)
comm_timeout = 0;
break;
}
case MODE_LIGHTSENSOR_READ: {
if (!adc_read_mode) {
// set the led and step to first step
adc_read_mode = 0;
adc_read_step = 0;
rgbled_sensor_read_idx(comm_data[0]);
adc_read_mode = ADC_MODE_LIGHTSENSOR;
}
// now we are ready to read.
// data will probably be prior data unless the host waits.
comm_timeout = 0;
break;
}
case MODE_SLEEP: {
// put this bitch to bed.
// we'll wake up when we get another I2C command.
pirate_sleep_mode = SLEEP_MODE_PWR_DOWN;
comm_cmd = 0;
comm_timeout = 0;
break;
}
// extended commands
case MODE_AUX_PIN_SET: {
// TODO: come up with an implementation that isn't shitty
}
case MODE_AUX_PIN_GET: {
// TODO: implement when response sending is ...implemented
comm_cmd = 0;
comm_timeout = 0;
break;
}
case MODE_LIGHTSENSOR_SENS: { // 0x10 0x19 <led 0-3> <sens 1-200>
if (comm_data_idx >= 1) {
if ((comm_data[0] <= 0x03) && (comm_data[1])) {
rgbled_sensor_sensitivity(comm_data[0], comm_data[1]);
}
comm_cmd = 0;
comm_timeout = 0;
}
break;
}
// invalid commands
default: {
// send NAK
comm_cmd = 0;
comm_timeout = 0;
return 1;
}
}
return 0;
}
static uint8_t pegleg_data_rx(uint8_t data)
{
if (comm_cmd == MODE_NONE) {
// we aren't processing any commands, so this must be a new command/request.
// first 4 bits = command
comm_cmd = data >> 4;
// last 4 bits = optional data
comm_data[0] = data & 0x0f;
// clear our data watchdog and data index
comm_data_idx = 0;
comm_timeout = 0;
// if this is an immediate command, process it
if (data & 0x80) {
return pegleg_cmd();
}
} else {
// command in progress - add data and continue
comm_data_idx++;
comm_data_idx &= (COMM_DATA_SIZE - 1); // data will LOOP in case of problems; TODO: NAK on failure
comm_data[comm_data_idx] = data;
return pegleg_cmd();
}
return 0;
}
#include "i2c_interrupt.h"
/* ISR handlers */
ISR(TIMER0_COMPA_vect)
{
/****
* this mainline loop runs at 2KHz, or 0.5ms.
* at the faster speed, this is ~3968 cycles/loop @8MHz.
****/
/* TIMEKEEPING */
// we only count a total of 10 seconds this way before we loop.
tim0_milli++;
if (tim0_milli >= 200) {
tim0_milli = 0;
tim0_centi++;
if (tim0_centi >= 100) {
tim0_centi = 0;
}
}
// 2khz fix. our timer isn't evenly divisible to get our 2K, so we do this...
OCR0A = (OCR0A == TIMER0_COMPARE) ? TIMER0_COMPARE + 1 : TIMER0_COMPARE;
/* ADC / LIGHT SENSOR / TEMP SENSOR */
// main adc handler
if (adc_read_mode) {
switch (adc_read_mode) {
case ADC_MODE_TEMPSENSOR: {
tempsensor_read();
break;
}
case ADC_MODE_LIGHTSENSOR: {
rgbled_sensor_read();
break;
}
}
if (adc_read_step <= 0xfe) {
adc_read_step++;
}
} /* else {
if (adc_read_step != 0xff) {
adc_read_step++;
if (adc_read_step == 0xff) {
// disable the ADC
ADCSRA &= ~(_BV(ADEN));
}
}
} */ // NOTE: we need to keep the ADC enabled; it takes too long to warm up.
/* LEDs */
// TODO: test common cathode mode
// figure out next LED to update (order is always RGB(X) repeating)
if (adc_read_mode != ADC_MODE_LIGHTSENSOR) {
rgbled_idx++;
#ifdef LED_RGBX_4LED
rgbled_idx &= 0x03;
#else
if (rgbled_idx > 2) {
rgbled_idx = 0;
}
#endif
// and now update them
rgbled_update();
}
/* COMMAND IO */
// stop processing the command if it isn't complete in 100ms.
if (comm_cmd != MODE_NONE) {
if (++comm_timeout >= 50) {
comm_cmd = MODE_NONE;
comm_timeout = 0;
i2c_disable_slave();
i2c_enable_slave();
}
}
/* PROFILING */
// determine how much CPU usage we are consuming
tim0_profiler = TCNT0;
}

110
attiny88_main/src/timer.h Normal file
View File

@ -0,0 +1,110 @@
/*
* timer.h
*
* Created: 5/21/2014 10:45:08 PM
* Author: true
*/
#ifndef TIMER_H_
#define TIMER_H_
#include "led.h"
#define TIMER0_COMPARE 62 - 1
#define TIMER1_COMPARE 252 - 1 // divisible by 63 which is set every other round for timer0
uint8_t timer1_mode;
/* prototypes */
/* implementations */
inline static void timer0_init()
{
// make sure timer is enabled
PRR &= ~PRTIM0;
// enable timer with prescale divider /64, enable TOP mode
TCCR0A = _BV(CTC0) | (_BV(CS00) | _BV(CS01) | ~(_BV(CS02)));
// set TOP level to be 62 to 63 counts; this will result in 2KHz cycle @8MHz
OCR0A = TIMER0_COMPARE;
// clear timer
TCNT0 = 0;
// and enable OCA interrupt (we don't use overflow interrupt as we are in TOP mode)
TIMSK0 = _BV(OCIE0A);
}
#define timer0_set_compare(x) OCR0A = x
inline static void timer1_init()
{
// make sure timer is enabled
PRR &= ~PRTIM1;
// clear PWM OCx
OCR1AH = 0xff; // sets temp register to 0xff
OCR1AL = 0xff;
OCR1BL = 0xff;
// clear timer
TCNT1H = 0; // sets temp register to 0
TCNT1L = 0;
// enable timer OC1 and OC2 clear on match / set at TOP, set to fast PWM mode 14 (ICR1 compare), prescaler off
// note: in PWM mode 14, pin PB0 can only be used as an output... =(
TCCR1A = (_BV(COM1A1)) | (_BV(COM1B1)) | (_BV(WGM11) | ~(_BV(WGM10)));
TCCR1B = (_BV(WGM12) | _BV(WGM13)) | (_BV(CS10));
TCCR1C = 0;
// store timer1 mode to allow enabling / disabling timer
timer1_mode = TCCR1A;
// set ICR compare to result in a PWM rate of 8MHz / 252, or 32256Hz
// This is 16 PWM updates per timer0 63-count period (16.25 per 62-count period)
// In practice we don't get the first PWM output, so we get:
// 15/16 PWM / (x) LEDs = 31.25% max duty for 3 LED, 23.43% max duty for 4 LED
ICR1L = TIMER1_COMPARE;
// set OC pins as outputs
DDRB |= (_BV(DDB2) | _BV(DDB1));
// disable interrupts
TIMSK1 = 0;
}
inline void timer1_pwm_reinit()
{
// enable pwm output on OCx pins
TCCR1A = (_BV(COM1A1)) | (_BV(COM1B1)) | (_BV(WGM11) | ~(_BV(WGM10)));
// set OC pins as outputs
DDRB |= (_BV(DDB2) | _BV(DDB1));
}
inline void timer1_set(uint16_t set)
{
TCNT1 = set;
}
#define timer1_disable() TCCR1A = 0
#define timer1_enable() TCCR1A = timer1_mode;
#ifdef LED_COMMON_ANODE
#define timer1_set_oca(v) OCR1AL = TIMER1_COMPARE - v
#define timer1_set_ocb(v) OCR1BL = TIMER1_COMPARE - v
#else
#define timer1_set_oca(v) OCR1AL = TIMER1_COMPARE
#define timer1_set_ocb(v) OCR1BL = TIMER1_COMPARE
#endif
#endif /* TIMER_H_ */

View File

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Atmel Studio Solution File, Format Version 11.00
Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "wp_dc22_attiny88", "wp_dc22_attiny88.cproj", "{0AAADF73-70F0-4C23-875D-53CCE8ABBF9B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|AVR = Debug|AVR
Release|AVR = Release|AVR
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0AAADF73-70F0-4C23-875D-53CCE8ABBF9B}.Debug|AVR.ActiveCfg = Debug|AVR
{0AAADF73-70F0-4C23-875D-53CCE8ABBF9B}.Debug|AVR.Build.0 = Debug|AVR
{0AAADF73-70F0-4C23-875D-53CCE8ABBF9B}.Release|AVR.ActiveCfg = Release|AVR
{0AAADF73-70F0-4C23-875D-53CCE8ABBF9B}.Release|AVR.Build.0 = Release|AVR
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<Store xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="AtmelPackComponentManagement">
<ProjectComponents>
<ProjectComponent z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<CApiVersion></CApiVersion>
<CBundle></CBundle>
<CClass>Device</CClass>
<CGroup>Startup</CGroup>
<CSub></CSub>
<CVariant></CVariant>
<CVendor>Atmel</CVendor>
<CVersion>1.3.0</CVersion>
<DefaultRepoPath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs</DefaultRepoPath>
<DependentComponents xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
<Description></Description>
<Files xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d4p1:anyType i:type="FileInfo">
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.3.172\include</AbsolutePath>
<Attribute></Attribute>
<Category>include</Category>
<Condition>C</Condition>
<FileContentHash i:nil="true" />
<FileVersion></FileVersion>
<Name>include</Name>
<SelectString></SelectString>
<SourcePath></SourcePath>
</d4p1:anyType>
<d4p1:anyType i:type="FileInfo">
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.3.172\include\avr\iotn88.h</AbsolutePath>
<Attribute></Attribute>
<Category>header</Category>
<Condition>C</Condition>
<FileContentHash>S2HUptOYqYmhL8kjFIMzIA==</FileContentHash>
<FileVersion></FileVersion>
<Name>include/avr/iotn88.h</Name>
<SelectString></SelectString>
<SourcePath></SourcePath>
</d4p1:anyType>
<d4p1:anyType i:type="FileInfo">
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.3.172\templates\main.c</AbsolutePath>
<Attribute>template</Attribute>
<Category>source</Category>
<Condition>C Exe</Condition>
<FileContentHash>GD1k8YYhulqRs6FD1B2Hog==</FileContentHash>
<FileVersion></FileVersion>
<Name>templates/main.c</Name>
<SelectString>Main file (.c)</SelectString>
<SourcePath></SourcePath>
</d4p1:anyType>
<d4p1:anyType i:type="FileInfo">
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.3.172\templates\main.cpp</AbsolutePath>
<Attribute>template</Attribute>
<Category>source</Category>
<Condition>C Exe</Condition>
<FileContentHash>YXFphlh0CtZJU+ebktABgQ==</FileContentHash>
<FileVersion></FileVersion>
<Name>templates/main.cpp</Name>
<SelectString>Main file (.cpp)</SelectString>
<SourcePath></SourcePath>
</d4p1:anyType>
<d4p1:anyType i:type="FileInfo">
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.3.172\gcc\dev\attiny88</AbsolutePath>
<Attribute></Attribute>
<Category>libraryPrefix</Category>
<Condition>GCC</Condition>
<FileContentHash i:nil="true" />
<FileVersion></FileVersion>
<Name>gcc/dev/attiny88</Name>
<SelectString></SelectString>
<SourcePath></SourcePath>
</d4p1:anyType>
</Files>
<PackName>ATtiny_DFP</PackName>
<PackPath>C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATtiny_DFP/1.3.172/Atmel.ATtiny_DFP.pdsc</PackPath>
<PackVersion>1.3.172</PackVersion>
<PresentInProject>true</PresentInProject>
<ReferenceConditionId>ATtiny88</ReferenceConditionId>
<RteComponents xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d4p1:string></d4p1:string>
</RteComponents>
<Status>Resolved</Status>
<VersionMode>Fixed</VersionMode>
<IsComponentInAtProject>true</IsComponentInAtProject>
</ProjectComponent>
</ProjectComponents>
</Store>

View File

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<ProjectVersion>7.0</ProjectVersion>
<ToolchainName>com.Atmel.AVRGCC8.C</ToolchainName>
<ProjectGuid>{0aaadf73-70f0-4c23-875d-53cce8abbf9b}</ProjectGuid>
<avrdevice>ATtiny88</avrdevice>
<avrdeviceseries>none</avrdeviceseries>
<OutputType>Executable</OutputType>
<Language>C</Language>
<OutputFileName>$(MSBuildProjectName)</OutputFileName>
<OutputFileExtension>.elf</OutputFileExtension>
<OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory>
<AssemblyName>wp_dc22_attiny88</AssemblyName>
<Name>wp_dc22_attiny88</Name>
<RootNamespace>wp_dc22_attiny88</RootNamespace>
<ToolchainFlavour>Native</ToolchainFlavour>
<KeepTimersRunning>true</KeepTimersRunning>
<OverrideVtor>false</OverrideVtor>
<CacheFlash>true</CacheFlash>
<ProgFlashFromRam>true</ProgFlashFromRam>
<RamSnippetAddress>0x20000000</RamSnippetAddress>
<UncachedRange />
<OverrideVtorValue>exception_table</OverrideVtorValue>
<BootSegment>2</BootSegment>
<eraseonlaunchrule>1</eraseonlaunchrule>
<AsfFrameworkConfig>
<framework-data>
<options />
<configurations />
<files />
<documentation help="" />
<offline-documentation help="" />
<dependencies>
<content-extension eid="atmel.asf" uuidref="Atmel.ASF" version="3.37" />
</dependencies>
</framework-data>
</AsfFrameworkConfig>
<preserveEEPROM>True</preserveEEPROM>
<avrtool>com.atmel.avrdbg.tool.simulator</avrtool>
<com_atmel_avrdbg_tool_simulator>
<ToolOptions xmlns="">
<InterfaceProperties>
<JtagEnableExtResetOnStartSession>false</JtagEnableExtResetOnStartSession>
</InterfaceProperties>
<InterfaceName>
</InterfaceName>
</ToolOptions>
<ToolType xmlns="">com.atmel.avrdbg.tool.simulator</ToolType>
<ToolNumber xmlns="">
</ToolNumber>
<ToolName xmlns="">Simulator</ToolName>
</com_atmel_avrdbg_tool_simulator>
<ResetRule>0</ResetRule>
<EraseKey />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<ToolchainSettings>
<AvrGcc>
<avrgcc.common.Device>-mmcu=attiny88 -B "%24(PackRepoDir)\atmel\ATtiny_DFP\1.3.172\gcc\dev\attiny88"</avrgcc.common.Device>
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>NDEBUG</Value>
</ListValues>
</avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATtiny_DFP\1.3.172\include</Value>
</ListValues>
</avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcc.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
</ListValues>
</avrgcc.linker.libraries.Libraries>
<avrgcc.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATtiny_DFP\1.3.172\include</Value>
</ListValues>
</avrgcc.assembler.general.IncludePaths>
</AvrGcc>
</ToolchainSettings>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<ToolchainSettings>
<AvrGcc>
<avrgcc.common.Device>-mmcu=attiny88 -B "%24(PackRepoDir)\atmel\ATtiny_DFP\1.3.172\gcc\dev\attiny88"</avrgcc.common.Device>
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATtiny_DFP\1.3.172\include</Value>
</ListValues>
</avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
<avrgcc.compiler.optimization.OtherFlags>-finline-functions</avrgcc.compiler.optimization.OtherFlags>
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcc.compiler.warnings.ExtraWarnings>True</avrgcc.compiler.warnings.ExtraWarnings>
<avrgcc.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
</ListValues>
</avrgcc.linker.libraries.Libraries>
<avrgcc.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATtiny_DFP\1.3.172\include</Value>
</ListValues>
</avrgcc.assembler.general.IncludePaths>
<avrgcc.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcc.assembler.debugging.DebugLevel>
</AvrGcc>
</ToolchainSettings>
</PropertyGroup>
<ItemGroup>
<Compile Include="src\adc.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="src\adc.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="src\config.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="src\i2c.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="src\i2c_interrupt.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="src\led.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="src\led.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="src\main.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="src\timer.h">
<SubType>compile</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="src" />
</ItemGroup>
<Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\Compiler.targets" />
</Project>