Skip to content

Instantly share code, notes, and snippets.

@nerdralph
Last active December 23, 2019 17:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nerdralph/4f2439af784fb08ab06e9fbcd378d98f to your computer and use it in GitHub Desktop.
Save nerdralph/4f2439af784fb08ab06e9fbcd378d98f to your computer and use it in GitHub Desktop.
prototype MicroCore OSCCAL tuner for ATtiny13
// t13 OSCCAL tuner
// Ralph Doncaster 2019 public domain software
// repeatedly press 'x' until OSCCAL value stabilizes
// output value is timing delta in cycles followed by OSCCAL
#define BAUD_RATE 115200
#include <BBUart.h>
#include <avr/sleep.h>
#define UART_RX 1
//extern int UART_RX;
#define DEBUGPIN 4
// converts 4-bit nibble to ascii hex
uint8_t nibbletohex(uint8_t value)
{
value &= 0x0F;
if ( value > 9 ) value += 'A' - ':';
return value + '0';
}
uint8_t printHex(uint8_t value)
{
TxByte(nibbletohex(value>>4));
TxByte(nibbletohex(value));
}
ISR(INT0_vect)
{
PINB |= 1<<DEBUGPIN; // toggle DEBUGPIN
// start timer when pin transitions low
if ((PINB & 1<<UART_RX) == 0)
TCCR0B = 1<<CS00;
else {
uint8_t current = TCNT0;
// end of interval, reset counter
TCCR0B = 0;
TCNT0 = 0;
// 'x' begins with 3 zeros + start bit = 4
// match speed to soft uart timing of 7 + TXDELAYCONT * 3
uint8_t expected = 4 * (7 + TXDELAYCOUNT * 3);
//uint8_t ideal_target = 4 * F_CPU / BAUD_RATE;
char delta = expected - current;
if (delta > 4) OSCCAL++;
if (delta < -4) OSCCAL--;
asm("lpm"); // 3 cycle delay
printHex(delta);
TxByte(' ');
printHex(OSCCAL);
TxByte('\n');
}
// clear interrupt flag in case another triggered
GIFR = 1<<INTF0;
}
void setup() {
// soft uart tx is PB3
digitalWrite(3,HIGH);
pinMode(3,OUTPUT);
pinMode(DEBUGPIN,OUTPUT);
MCUCR |= 1 << SE; // sleep enable
digitalWrite(UART_RX,HIGH); // pullup
delay(1000); // pause after startup
wait_x:
TxByte('x');
TxByte('\n');
// wait for tuning character to ensure not reading noise
// before entering tuning mode
uint8_t counter = 0;
while (PINB & (1<<UART_RX));
do {
counter++;
} while ((PINB & (1<<UART_RX)) == 0);
// low period should be 4 bit-times for 'x'
// counter loop is 4 cycles, so counter =~ BIT_CYCLES
uint8_t margin = BIT_CYCLES/8;
if ( counter - (uint8_t)BIT_CYCLES > margin ) goto wait_x;
else
if ( (uint8_t)BIT_CYCLES - counter > margin ) goto wait_x;
delay(1); // skip remaining bits in frame
TxByte('I'); // debug enabling INTO
printHex(OSCCAL);
TxByte('\n');
// reset counter for first interrupt
TCCR0B = 0;
TCNT0 = 0;
// setup interrupt on Rx pin, any change on INTO
GIMSK = 1<<INT0;
MCUCR |= (1<<ISC00);
sei();
}
void loop() {
// nothing to see here
asm("sleep");
//sleep_cpu();
}
@nerdralph
Copy link
Author

v3 changes:
switch from digitalRead() to direct register reading to ensure fastest port reading.
reset timer/counter before enabling ISR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment