mirror of
https://github.com/opentx/opentx.git
synced 2025-07-23 16:25:16 +03:00
929 lines
28 KiB
C
929 lines
28 KiB
C
//#include <ioavr.h>
|
||
#include <inttypes.h>
|
||
#include <avr/io.h>
|
||
#include <avr/pgmspace.h>
|
||
#include <avr/boot.h>
|
||
#include "stdint.h"
|
||
//#include <inavr.h>
|
||
#include "Common_Define.h"
|
||
#include <util/delay.h>
|
||
#include <avr/wdt.h>
|
||
#include <avr/interrupt.h>
|
||
#include <avr/sleep.h>
|
||
|
||
#include "USI_TWI_Slave.h"
|
||
|
||
#define sbi(port,bit) (port |= (1<<bit)) //set bit in port
|
||
#define cbi(port,bit) (port &= ~(1<<bit)) //clear bit in port
|
||
#define SLEEP_MODE_PWR_SAVE (_BV(SM0) | _BV(SM1))
|
||
#define FORCE_INDIRECT(ptr) __asm__ __volatile__ ("" : "=e" (ptr) : "0" (ptr))
|
||
#define NOINLINE __attribute__ ((noinline))
|
||
|
||
// Version number, sent in first byte of response
|
||
#define VERSION 0x03
|
||
|
||
/*****************************************************************************/
|
||
// USI_TWI write states.
|
||
#define USI_TWI_WRITE_ADDR_HI_BYTE (0x00)
|
||
#define USI_TWI_WRITE_ADDR_LO_BYTE (0x01)
|
||
#define USI_TWI_WRITE_DATA_BYTE (0x02)
|
||
|
||
// USI_TWI overflow states.
|
||
#define USI_TWI_OVERFLOW_STATE_NONE (0x00)
|
||
#define USI_TWI_OVERFLOW_STATE_ACK_PR_RX (0x01)
|
||
#define USI_TWI_OVERFLOW_STATE_DATA_RX (0x02)
|
||
#define USI_TWI_OVERFLOW_STATE_ACK_PR_TX (0x03)
|
||
#define USI_TWI_OVERFLOW_STATE_PR_ACK_TX (0x04)
|
||
#define USI_TWI_OVERFLOW_STATE_DATA_TX (0x05)
|
||
|
||
#define DATA_SIZE 16 // Receive data buffer size
|
||
|
||
#define TEMPERATURE 0b01001011
|
||
|
||
// Signature row addresses
|
||
#define TSOFFSET 5
|
||
#define TSGAIN 7
|
||
|
||
// Bits in AdcControl
|
||
#define ADC_RUNNING 0x80
|
||
#define ADC_COUNT_MASK 0x0F
|
||
|
||
uint8_t AdcControl ;
|
||
uint16_t AdcTotal ;
|
||
int8_t T_offset ;
|
||
uint8_t T_gain ;
|
||
int16_t T_mult ;
|
||
|
||
// USI_TWI state values.
|
||
static uint8_t USI_TWI_SLAVE_Write_State;
|
||
static uint8_t USI_TWI_SLAVE_Overflow_State;
|
||
static uint8_t Command_Flag;
|
||
|
||
// TWI flag values.
|
||
// static uint8_t USI_TWI_SLAVE_Address_Update;
|
||
|
||
// Slave Each page address values.
|
||
//static uint16_t USI_TWI_SLAVE_PAGE_Address;
|
||
|
||
uint8_t DataBuffer[DATA_SIZE];
|
||
static uint8_t *bufferPtr ;
|
||
static uint8_t Value;
|
||
uint8_t Tx_buffer[22] ;
|
||
int8_t Temperature;
|
||
static uint8_t Tx_index ;
|
||
|
||
typedef struct
|
||
{
|
||
unsigned char second; //enter the current time, date, month, and year
|
||
unsigned char minute;
|
||
unsigned char hour;
|
||
unsigned char date;
|
||
unsigned char month;
|
||
unsigned int year;
|
||
} t_time ;
|
||
|
||
t_time Time ;
|
||
|
||
uint8_t ActivityFlag ;
|
||
|
||
void main (void) __attribute__((noreturn)) ;
|
||
char not_leap(void) ; //check for leap year
|
||
void updateTime(uint8_t amount) ;
|
||
void set_clock( uint8_t speed ) ;
|
||
void checkPowerSave( void ) ;
|
||
static void Disable_WatchDogTimer(void) ;
|
||
static void Init_WatchDogTimer(void) ;
|
||
void enableAdc( void ) ;
|
||
void disableAdc( void ) ;
|
||
|
||
|
||
char not_leap(void) //check for leap year
|
||
{
|
||
t_time *p = &Time ;
|
||
FORCE_INDIRECT(p) ;
|
||
if (!(p->year%100))
|
||
return (char)(p->year%400);
|
||
else
|
||
return (char)(p->year%4);
|
||
}
|
||
|
||
void updateTime(uint8_t amount)
|
||
{
|
||
t_time *p = &Time ;
|
||
FORCE_INDIRECT(p) ;
|
||
|
||
if (++p->second >= 60) //keep track of time, date, month, and year
|
||
{
|
||
p->second -= 60 ;
|
||
if (++p->minute >= 60)
|
||
{
|
||
p->minute=0;
|
||
if (++p->hour >= 24)
|
||
{
|
||
p->hour=0;
|
||
if (++p->date >= 32)
|
||
{
|
||
p->month++;
|
||
p->date=1;
|
||
}
|
||
else if (p->date == 31)
|
||
{
|
||
if ((p->month==4) || (p->month==6) || (p->month==9) || (p->month==11))
|
||
{
|
||
p->month++;
|
||
p->date=1;
|
||
}
|
||
}
|
||
else if (p->date==30)
|
||
{
|
||
if(p->month==2)
|
||
{
|
||
p->month++;
|
||
p->date=1;
|
||
}
|
||
}
|
||
else if (p->date==29)
|
||
{
|
||
if((p->month==2) && (not_leap()))
|
||
{
|
||
p->month++;
|
||
p->date=1;
|
||
}
|
||
}
|
||
if (p->month >= 13)
|
||
{
|
||
p->month=1;
|
||
p->year++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
ISR(TIMER0_OVF_vect)
|
||
{
|
||
TCCR0B = 5 ; // Divide/128
|
||
while((ASSR & 0b00011011) != 0x00);/*Wait until TCNT0, OCR0A, TCCR0A and TCCR0B updated*/
|
||
updateTime(1) ;
|
||
}
|
||
|
||
void checkPowerSave()
|
||
{
|
||
if ( PINB & 0x05 )
|
||
{
|
||
ActivityFlag = 0 ;
|
||
return ; // I2C line(s) are high, power is ON
|
||
}
|
||
if ( ActivityFlag < 3 )
|
||
{
|
||
return ;
|
||
}
|
||
|
||
// The AVR toolchain includes a header file, sleep.h, which has functions for setting
|
||
//sleep mode, disabling BOD, and putting the device into sleep. These functions are
|
||
//called:
|
||
//.. set_sleep_mode() <20> selects which sleep mode to use when the sleep
|
||
//instruction is executed
|
||
//.. sleep_enable() <20> enables sleep modes
|
||
//.. sleep_bod_disable() <20> disables BOD while sleeping
|
||
//.. sleep_cpu() <20> executes the sleep instruction
|
||
|
||
CLKPR = 0x80 ; // Do inline for quick response
|
||
CLKPR = 0 ; // Full speed 8.0MHz
|
||
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
|
||
TIMSK0 |= (1 << TOIE0) ;
|
||
disableAdc() ;
|
||
PRR = 0x3B ; // Power off USI
|
||
Disable_WatchDogTimer() ;
|
||
set_clock( 2 ) ; // Slow to 2.0 MHz
|
||
while ( ( PINB & 0x05 ) == 0 ) // I2C lines are low
|
||
{
|
||
sleep_enable();
|
||
sleep_bod_disable();
|
||
sei();
|
||
sleep_cpu();
|
||
sleep_disable();
|
||
cli() ;
|
||
wdt_reset() ;
|
||
}
|
||
PRR = 0x39 ; // USI re-powered
|
||
Init_WatchDogTimer() ;
|
||
USI_TWI_SLAVE_Init();
|
||
enableAdc() ;
|
||
TIMSK0 &= ~(1 << TOIE0) ;
|
||
USISR = (1<<USISIF) | (1<<USIOIF) | (1<<USIPF) ; // Clear interrupt flags.
|
||
set_clock( 5 ) ; // Slow to 0.25MHz
|
||
ActivityFlag = 0 ;
|
||
}
|
||
|
||
|
||
/******************************************************************************/
|
||
|
||
/* Local variables */
|
||
//static uint8_t TWI_RxBuf[TWI_RX_BUFFER_SIZE];
|
||
//static volatile uint8_t TWI_RxHead;
|
||
//static volatile uint8_t TWI_RxTail;
|
||
|
||
//static uint8_t TWI_TxBuf[TWI_TX_BUFFER_SIZE];
|
||
//static volatile uint8_t TWI_TxHead;
|
||
//static volatile uint8_t TWI_TxTail;
|
||
|
||
#define USI_TWI_SlaveAddress 0x35
|
||
|
||
//********** USI_TWI functions **********//
|
||
static void USI_TWI_SLAVE_Init()
|
||
{
|
||
|
||
// USI_TWI_SlaveAddress = TWI_OwnAddress;
|
||
|
||
DDR_USI &= ~(1<<PORT_USI_SDA); // Set SDA as input
|
||
PORT_USI &= ~(1<<PORT_USI_SDA); // Set SDA high
|
||
|
||
DDR_USI |= (1<<PORT_USI_SCL); // Set SCL as output
|
||
PORT_USI |= (1<<PORT_USI_SCL); // Set SCL high
|
||
|
||
|
||
USICR = /*(0<<USISIE)|(0<<USIOIE)|*/ // Disable Start Condition Interrupt. Disable Overflow Interrupt.
|
||
(1<<USIWM1)|(1<<USIWM0)| // Set USI in Two-wire mode. No USI Counter overflow prior
|
||
// to first Start Condition (potentail failure)
|
||
(1<<USICS1)|(0<<USICS0)|(0<<USICLK)| // Shift Register Clock Source = External, positive edge
|
||
(0<<USITC);
|
||
|
||
// Clear the interrupt flags and reset the counter.
|
||
USISR = (1<<USISIF) | (1<<USIOIF) | (1<<USIPF) | // Clear interrupt flags.
|
||
(1<<USIDC) |(0x0<<USICNT0); // USI to sample 8 bits or 16 edge toggles.
|
||
|
||
// USI TWI Start condition interrupt enable.
|
||
// USICR |= (1<<USISIE); // Not needed, all are polled
|
||
}
|
||
|
||
// the below function is added by
|
||
/*****************************************************************************/
|
||
static void USI_TWI_SLAVE_Abort()
|
||
{
|
||
USICR = /*(0<<USISIE)|(0<<USIOIE)|*/ // Disable Start Condition Interrupt. Disable Overflow Interrupt.
|
||
(0<<USIWM1)|(0<<USIWM0)| // reset USI in Two-wire mode. No USI Counter overflow prior
|
||
// to first Start Condition (potentail failure)
|
||
(0<<USICS1)|(0<<USICS0)|(0<<USICLK)| // Shift Register Clock Source = internal, positive edge
|
||
(0<<USITC);
|
||
|
||
|
||
// Reset SCL and SDA lines of TWI Communication interface
|
||
DDR_USI &= ~(1<<PORT_USI_SDA);
|
||
PORT_USI &= ~(1<<PORT_USI_SDA); // Set SDA low
|
||
// PORTA &= ~8 ;
|
||
|
||
DDR_USI |= ~(1<<PORT_USI_SCL);
|
||
PORT_USI |= ~(1<<PORT_USI_SCL); // Set SCL low
|
||
|
||
// Clear the USI DATA register.
|
||
USIDR = 0x00;
|
||
|
||
// Clear the interrupt flags and reset the counter.
|
||
USISR = (1<<USISIF) | (1<<USIOIF) | (1<<USIPF) | // Clear interrupt flags.
|
||
(1<<USIDC) |(0x0<<USICNT0); // USI to sample 8 bits or 16 edge toggles.
|
||
|
||
}
|
||
|
||
|
||
static void USI_TWI_SLAVE_ReadAndProcessPacket ()
|
||
{
|
||
set_clock( 5 ) ; // Slow to 0.25MHz
|
||
while(1)
|
||
{
|
||
// Check for USI TWI start condition.
|
||
if (USISR & (1<<USISIF))
|
||
{
|
||
CLKPR = 0x80 ; // Do inline for quick response
|
||
CLKPR = 0 ; // Full speed 8.0MHz
|
||
// Process the USI TWI start condition.
|
||
USI_TWI_SLAVE_Process_Start_Condition();
|
||
|
||
}
|
||
|
||
// Check for USI_TWI_SLAVE overflow condition.
|
||
if (USISR & (1<<USIOIF))
|
||
{
|
||
ActivityFlag = 0 ;
|
||
// Handle the TWI overflow condition.
|
||
USI_TWI_SLAVE_Process_Overflow_Condition();
|
||
|
||
/* as this part is already taken care...
|
||
// Should we update the twi address?
|
||
if (USI_TWI_SLAVE_Address_Update)
|
||
{
|
||
// Mark the bootloader as active.
|
||
bootloader_active = 1;
|
||
|
||
// Check for the special address to exit the bootloader.
|
||
if (USI_TWI_SLAVE_PAGE_Address != 0xffff)
|
||
{
|
||
// Set the twi address. This will load the corresponding page from
|
||
// flash into the programming buffer for reading and writing.
|
||
// prog_buffer_set_address(USI_TWI_SLAVE_PAGE_Address);
|
||
}
|
||
|
||
// Reset the flag.
|
||
USI_TWI_SLAVE_Address_Update = 0;
|
||
}
|
||
|
||
.....Till here.........*/
|
||
|
||
}
|
||
|
||
// Check for TWI stop condition.
|
||
if (USISR & (1<<USIPF))
|
||
{
|
||
// Clear the stop condition flag.
|
||
USISR = (1<<USIPF);
|
||
// Check for the special address to exit the bootloader.
|
||
if ( Run_boot )
|
||
{
|
||
// Set the flag to have the bootloader eixt.
|
||
break ;
|
||
}
|
||
else
|
||
{
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_NONE ;
|
||
Command_Flag = 0 ;
|
||
}
|
||
set_clock( 5 ) ; // Slow to 0.25MHz
|
||
}
|
||
wdt_reset() ;
|
||
|
||
if ( TIFR0 & 1 )
|
||
{
|
||
CLKPR = 0x80 ; // Do inline for quick response
|
||
CLKPR = 0 ; // Full speed 8.0MHz
|
||
|
||
TIFR0 = 1 ; // CLEAR flag (write 1)
|
||
updateTime(1) ;
|
||
t_time *p = &Time ;
|
||
uint8_t *q = &Tx_buffer[1] ;
|
||
// FORCE_INDIRECT(p) ;
|
||
|
||
*q++ = p->second ;
|
||
*q++ = p->minute ;
|
||
*q++ = p->hour ;
|
||
*q++ = p->date ;
|
||
*q++ = p->month ;
|
||
*q++ = p->year ;
|
||
*q++ = p->year >> 8 ;
|
||
*q++ = Temperature ;
|
||
*q++ = T_offset ;
|
||
*q++ = T_gain ;
|
||
// *q++ = MCUSR ;
|
||
|
||
if ( ActivityFlag < 255 )
|
||
{
|
||
ActivityFlag += 1 ;
|
||
}
|
||
set_clock( 5 ) ; // Slow to 0.25MHz
|
||
}
|
||
|
||
checkPowerSave() ;
|
||
|
||
if ( ( AdcControl & ADC_RUNNING ) == 0 )
|
||
{
|
||
ADMUX = TEMPERATURE ; // Internal 1.1V REF and ADCx
|
||
ADCSRA |= (1<<ADSC); // do single conversion
|
||
AdcControl |= ADC_RUNNING ;
|
||
}
|
||
else
|
||
{
|
||
if ( ( ADCSRA & (1<<ADSC) ) == 0 )
|
||
{
|
||
AdcControl &= ~ADC_RUNNING ;
|
||
AdcControl += 1 ;
|
||
if ( ( AdcControl & ADC_COUNT_MASK ) > 1 )
|
||
{ // Skip first conversion
|
||
AdcTotal += ADCW ;
|
||
}
|
||
if ( ( AdcControl & ADC_COUNT_MASK ) >= 9 )
|
||
{
|
||
AdcTotal += 4 ;
|
||
AdcTotal >>= 3 ;
|
||
{
|
||
int16_t temp ;
|
||
|
||
temp = AdcTotal ;
|
||
temp -= 298 ;
|
||
temp += T_offset ;
|
||
temp *= T_mult ;
|
||
temp >>= 8 ;
|
||
temp += 25 ;
|
||
Temperature = temp ;
|
||
}
|
||
AdcControl = 0 ;
|
||
AdcTotal = 0 ;
|
||
|
||
|
||
// if (AdcTotal < 0x00f6)
|
||
// {
|
||
// Temperature=-40;
|
||
// }
|
||
// else if (AdcTotal < 0x0144)
|
||
// {
|
||
// Temperature=((AdcTotal*78)/65)-40;
|
||
// }
|
||
// else
|
||
// {
|
||
// Temperature=((((AdcTotal-324)*600)/74)+250)/10;
|
||
// }
|
||
}
|
||
}
|
||
}
|
||
} // while
|
||
// Disable_WatchDogTimer(); // After Reset the WDT state does not change
|
||
// void (*FuncPtr) (void) = (void (*)(void)) (0x0080); // Set up function pointer to address 0x0080
|
||
// FuncPtr ();
|
||
TCCR0B = 0 ;
|
||
USICR = 0 ;
|
||
USISR = 0 ;
|
||
PRR = 0 ;
|
||
CLKPR = 0x80 ; // Do inline for quick response
|
||
CLKPR = 0 ; // Full speed 8.0MHz
|
||
((void (*)(void)) (0))() ;
|
||
}
|
||
|
||
|
||
/******************************************************************************/
|
||
//Description:
|
||
// Process the USI TWI start condition. This is called when the TWI master initiates
|
||
// communication with a USI TWI slave by asserting the TWI start condition.
|
||
/******************************************************************************/
|
||
static void USI_TWI_SLAVE_Process_Start_Condition(void)
|
||
{
|
||
// Wait until the "Start Condition" is complete when SCL goes low. If we fail to wait
|
||
// for SCL to go low we may miscount the number of clocks pulses for the data because
|
||
// the transition of SCL could be mistaken as one of the data clock pulses.
|
||
while ((PIN_USI & (1<<PORT_USI_SCL)));
|
||
// Reset the overflow state.
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_NONE;
|
||
// Clear the interrupt flags and reset the counter.
|
||
USISR = (1<<USISIF) | (1<<USIOIF) | (1<<USIPF) | // Clear interrupt flags.
|
||
(0x00<<USICNT0); // USI to sample 8 bits or 16 edge toggles.
|
||
|
||
// Update the interrupt enable, wire mode and clock settings.
|
||
USICR = /*(1<<USISIE) | (1<<USIOIE) |*/ // Enable Overflow and Start Condition Interrupt.
|
||
(1<<USIWM1) | (1<<USIWM0) | // Maintain USI in two-wire mode with clock stretching.
|
||
(1<<USICS1) | (0<<USICS0) | (0<<USICLK) | // Shift Register Clock Source = External, positive edge
|
||
(0<<USITC); // No toggle of clock pin.
|
||
}
|
||
|
||
/******************************************************************************/
|
||
|
||
|
||
/*******************************************************************************
|
||
Description:
|
||
Processes the USI_TWI_SLAVE overflow condition.
|
||
This is called when the USI TWI 4-bit counterboverflows indicating the
|
||
TWI master has clocked in/out a databyte or a singleback/nack byte following a
|
||
databyte transfer.
|
||
|
||
*******************************************************************************/
|
||
void USI_TWI_SLAVE_Process_Overflow_Condition(void)
|
||
{
|
||
// Buffer the USI data.
|
||
uint8_t Usi_Data = USIDR;
|
||
|
||
// Handle the interrupt based on the overflow state.
|
||
switch (USI_TWI_SLAVE_Overflow_State)
|
||
{
|
||
/***********************************************************************/
|
||
// Handle the first byte transmitted from master -- the slave address.
|
||
case USI_TWI_SLAVE_OVERFLOW_STATE_NONE:
|
||
|
||
// Are we receiving our address?
|
||
if ((Usi_Data >> 1) == USI_TWI_SlaveAddress)
|
||
{
|
||
// Yes. Are we to send or receive data?
|
||
if((Usi_Data & 0x01) == 0x01)
|
||
{
|
||
//USI TWI Slave has to transmit the data byte
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_ACK_PR_TX;
|
||
Tx_buffer[0] = VERSION ; // Version number
|
||
Tx_index = 0 ;
|
||
}
|
||
else
|
||
{
|
||
//USI TWI Slave has to Receive the data byte
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_ACK_PR_RX;
|
||
}
|
||
|
||
// Reset the write state.
|
||
//.. added the below statement at Command_flag=1
|
||
//USI_TWI_SLAVE_Write_State = USI_TWI_SLAVE_WRITE_ADDR_HI_BYTE;
|
||
|
||
// Set SDA for output.
|
||
PORT_USI |= (1<<PORT_USI_SDA);
|
||
DDR_USI |= (1<<PORT_USI_SDA);
|
||
|
||
// Load data for ACK.
|
||
USIDR = 0;
|
||
|
||
// Reload counter for ACK -- two clock transitions.
|
||
USISR = 0x0E;
|
||
|
||
}
|
||
else
|
||
{
|
||
// No. Reset USI to detect start condition. Update the interrupt enable,
|
||
// wire mode and clock settings. Note: At this time the wire mode must
|
||
// not be set to hold the SCL line low when the counter overflows.
|
||
// Otherwise, this TWI slave will interfere with other TWI slaves.
|
||
USICR = /*(1<<USISIE) | (0<<USIOIE) |*/ // Enable Start Condition Interrupt. Disable overflow.
|
||
(1<<USIWM1) | (0<<USIWM0) | // Maintain USI in two-wire mode without clock stretching.
|
||
(1<<USICS1) | (0<<USICS0) | (0<<USICLK) | // Shift Register Clock Source = External, positive edge
|
||
(0<<USITC); // No toggle of clock pin.
|
||
}
|
||
|
||
break;
|
||
/***********************************************************************/
|
||
// Ack sent to master so prepare to receive more data.
|
||
case USI_TWI_SLAVE_OVERFLOW_STATE_ACK_PR_RX:
|
||
|
||
if(Command_Flag == 0)
|
||
{
|
||
// Update our state.
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_CMD_RX;
|
||
}
|
||
else if(Command_Flag == 1)
|
||
{
|
||
// Update our state.
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_DATA_RX;
|
||
}
|
||
// else if(Command_Flag == 2)
|
||
// {
|
||
// // Update our state.
|
||
// USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_DATA_TX_AVERSION;
|
||
// }
|
||
// else if(Command_Flag == 3)
|
||
// {
|
||
// // Update our state.
|
||
// USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_DATA_TX_BVERSION;
|
||
// }
|
||
// else if(Command_Flag == 4)
|
||
// {
|
||
// // Update our state.
|
||
// USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_DATA_TX_GETERRCONDN;
|
||
// }
|
||
|
||
|
||
// Set SDA for input
|
||
DDR_USI &= ~(1<<PORT_USI_SDA);
|
||
PORT_USI &= ~(1<<PORT_USI_SDA);
|
||
|
||
break;
|
||
/**************************************************************************/
|
||
|
||
|
||
case USI_TWI_SLAVE_OVERFLOW_STATE_CMD_RX:
|
||
|
||
// Update our state
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_NONE;
|
||
|
||
// Check the command received type.
|
||
if(Usi_Data == TWI_CMD_REBOOT)
|
||
{
|
||
// reset the controller ...
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_ACK_PR_RX ;
|
||
// set this flag to receive data
|
||
Command_Flag = 0 ;
|
||
Run_boot = 1 ;
|
||
}
|
||
else if(Usi_Data == TWI_CMD_WRITE_DATA)
|
||
{
|
||
// set this flag to receive data
|
||
Command_Flag =1;
|
||
// ReceiveType = TWI_CMD_SETDATETIME ;
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_ACK_PR_RX ;
|
||
USI_TWI_SLAVE_Write_State = USI_TWI_SLAVE_WRITE_DATA_BYTE;
|
||
bufferPtr = DataBuffer ;
|
||
Value = 0 ;
|
||
}
|
||
// else if(Usi_Data == TWI_CMD_BVERSION)
|
||
// {
|
||
// // set this flag to receive data
|
||
// Command_Flag =3;
|
||
|
||
// }
|
||
// else if(Usi_Data == TWI_CMD_ERASEFLASH)
|
||
// {
|
||
// // erase the flash here itself .......
|
||
|
||
// // set this flag to receive data
|
||
// Command_Flag =0;
|
||
|
||
// }
|
||
// else if(Usi_Data == TWI_CMD_GETERRCONDN)
|
||
// {
|
||
// // set this flag to receive data
|
||
// Command_Flag =4;
|
||
|
||
// }
|
||
else
|
||
{
|
||
// set this flag to receive data
|
||
Command_Flag =0;
|
||
|
||
USI_TWI_SLAVE_Abort();
|
||
}
|
||
// Set SDA for output.
|
||
PORT_USI |= (1<<PORT_USI_SDA);
|
||
DDR_USI |= (1<<PORT_USI_SDA);
|
||
|
||
// Load data for ACK.
|
||
USIDR = 0;
|
||
|
||
// Reload counter for ACK -- two clock transitions.
|
||
USISR = 0x0E;
|
||
break;
|
||
|
||
// Data received from master so prepare to send ACK.
|
||
case USI_TWI_SLAVE_OVERFLOW_STATE_DATA_RX:
|
||
|
||
// Update our state.
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_ACK_PR_RX;
|
||
|
||
// Always make sure the Command_Flag is 1
|
||
Command_Flag = 1;
|
||
|
||
// Check the TWI write state to determine what type of byte we received.
|
||
// if (USI_TWI_SLAVE_Write_State == USI_TWI_SLAVE_WRITE_ADDR_HI_BYTE)
|
||
// {
|
||
// // Set the twi address high byte.
|
||
// USI_TWI_SLAVE_PAGE_Address = Usi_Data;
|
||
|
||
// // Set the next state.
|
||
// USI_TWI_SLAVE_Write_State = USI_TWI_SLAVE_WRITE_ADDR_LO_BYTE;
|
||
// }
|
||
// else if (USI_TWI_SLAVE_Write_State == USI_TWI_SLAVE_WRITE_ADDR_LO_BYTE)
|
||
// {
|
||
// // Set the address low byte.
|
||
// USI_TWI_SLAVE_PAGE_Address = (USI_TWI_SLAVE_PAGE_Address << 8) | Usi_Data;
|
||
|
||
// // Set the programming address.
|
||
//// USI_TWI_SLAVE_Address_Update = 1;
|
||
// Value = 0;
|
||
// bufferPtr = pageBuffer ;
|
||
|
||
// // Set the next state.
|
||
// USI_TWI_SLAVE_Write_State = USI_TWI_SLAVE_WRITE_DATA_BYTE;
|
||
// }
|
||
// else
|
||
{
|
||
// Write the data to the buffer.
|
||
//USI_TWI_SLAVE_prog_buffer_set_byte(Usi_Data);
|
||
|
||
*bufferPtr = Usi_Data;
|
||
|
||
// Increment the byte address within the page.
|
||
//++prog_byte_address;
|
||
|
||
++bufferPtr;
|
||
++Value;
|
||
// Check the byte address for wrapping. // check later
|
||
|
||
if ( DataBuffer[0] == TWI_SUBCMD_SETDATETIME )
|
||
{
|
||
if (Value >= 8 ) // Size of time structure+1
|
||
{
|
||
if ( Value == 8 )
|
||
{
|
||
// Set the date and time
|
||
t_time *p = &Time ;
|
||
FORCE_INDIRECT(p) ;
|
||
|
||
p->second = DataBuffer[1] ;
|
||
p->minute = DataBuffer[2] ;
|
||
p->hour = DataBuffer[3] ;
|
||
p->date= DataBuffer[4] ;
|
||
p->month = DataBuffer[5] ;
|
||
p->year = DataBuffer[6] + ( DataBuffer[7] << 8 ) ;
|
||
}
|
||
Value = 9 ;
|
||
bufferPtr = &DataBuffer[DATA_SIZE-1] ;
|
||
}
|
||
}
|
||
if ( Value > DATA_SIZE )
|
||
{
|
||
Value = DATA_SIZE ;
|
||
bufferPtr = &DataBuffer[DATA_SIZE-1] ; // Overwrite last byte
|
||
}
|
||
}
|
||
|
||
// Set SDA for output.
|
||
PORT_USI |= (1<<PORT_USI_SDA);
|
||
DDR_USI |= (1<<PORT_USI_SDA);
|
||
// PORTA |= 8 ;
|
||
|
||
// Load data for ACK.
|
||
USIDR = 0;
|
||
|
||
// Reload counter for ACK -- two clock transitions.
|
||
USISR = 0x0E;
|
||
|
||
break;
|
||
/***********************************************************************/
|
||
|
||
case USI_TWI_SLAVE_OVERFLOW_STATE_DATA_TX_AVERSION:
|
||
|
||
// Update our state.
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_PR_ACK_TX;
|
||
|
||
// Set SDA for input.
|
||
DDR_USI &= ~(1<<PORT_USI_SDA);
|
||
// PORTA &= ~8 ;
|
||
PORT_USI &= ~(1<<PORT_USI_SDA);
|
||
|
||
// Reload counter for ACK -- two clock transitions.
|
||
USISR = 0x0E;
|
||
|
||
break;
|
||
|
||
/***********************************************************************/
|
||
case USI_TWI_SLAVE_OVERFLOW_STATE_DATA_TX_BVERSION:
|
||
|
||
break;
|
||
/***********************************************************************/
|
||
case USI_TWI_SLAVE_OVERFLOW_STATE_DATA_TX_GETERRCONDN:
|
||
|
||
break;
|
||
/***********************************************************************/
|
||
// ACK received from master. Reset USI state if NACK received.
|
||
case USI_TWI_SLAVE_OVERFLOW_STATE_PR_ACK_TX:
|
||
|
||
// Check the lowest bit for NACK? If set, the master does not want more data.
|
||
if (Usi_Data & 0x01)
|
||
{
|
||
// Update our state.
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_NONE;
|
||
|
||
// Reset USI to detect start condition. Update the interrupt enable,
|
||
// wire mode and clock settings. Note: At this time the wire mode must
|
||
// not be set to hold the SCL line low when the counter overflows.
|
||
// Otherwise, this TWI slave will interfere with other TWI slaves.
|
||
USICR = /*(1<<USISIE) | (0<<USIOIE) |*/ // Enable Start Condition Interrupt. Disable overflow.
|
||
(1<<USIWM1) | (0<<USIWM0) | // Maintain USI in two-wire mode without clock stretching.
|
||
(1<<USICS1) | (0<<USICS0) | (0<<USICLK) | // Shift Register Clock Source = External, positive edge
|
||
(0<<USITC); // No toggle of clock pin.
|
||
|
||
|
||
// Clear the overflow interrupt flag and release the hold on SCL.
|
||
USISR |= (1<<USIOIF);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
/***********************************************************************/
|
||
// Handle sending a byte of data.
|
||
case USI_TWI_SLAVE_OVERFLOW_STATE_ACK_PR_TX:
|
||
|
||
// Update our state.
|
||
// USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_DATA_TX;
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_DATA_TX_AVERSION;
|
||
|
||
// Set SDA for output.
|
||
PORT_USI |= (1<<PORT_USI_SDA);
|
||
DDR_USI |= (1<<PORT_USI_SDA);
|
||
// PORTA |= 8 ;
|
||
|
||
// Get the data to send.
|
||
// USIDR = prog_buffer_get_byte();
|
||
|
||
USIDR = Tx_buffer[Tx_index++] ; // Send this for testing
|
||
|
||
break;
|
||
/***********************************************************************/
|
||
|
||
// Data sent to to master so prepare to receive ack.
|
||
case USI_TWI_SLAVE_OVERFLOW_STATE_DATA_TX:
|
||
|
||
// Update our state.
|
||
USI_TWI_SLAVE_Overflow_State = USI_TWI_SLAVE_OVERFLOW_STATE_PR_ACK_TX;
|
||
|
||
// Set SDA for input.
|
||
DDR_USI &= ~(1<<PORT_USI_SDA);
|
||
// PORTA &= ~8 ;
|
||
PORT_USI &= ~(1<<PORT_USI_SDA);
|
||
|
||
// Reload counter for ACK -- two clock transitions.
|
||
USISR = 0x0E;
|
||
|
||
break;
|
||
/***********************************************************************/
|
||
}
|
||
// Clear the overflow interrupt flag and release the hold on SCL.
|
||
USISR |= (1<<USIOIF);
|
||
}
|
||
|
||
uint8_t state = 0;
|
||
// __no_init uint8_t pageBuffer[PAGE_SIZE];
|
||
//uint16_t time_lapse_sec = 0;
|
||
#define gtimeout WDT_TIMEOUT_8s
|
||
// uint8_t volatile gtimeout;
|
||
//uint8_t statusCode = 0;
|
||
|
||
/***********************************************************************/
|
||
|
||
static void Disable_WatchDogTimer (void)
|
||
{
|
||
/*
|
||
Timed sequence
|
||
Interrupts are already disabled else additional code may go in to avoid
|
||
the servicing of interrupt in between the timed sequence
|
||
*/
|
||
wdt_reset();
|
||
WDTCR = (1 << WDCE) | ( 1 << WDE ) ;
|
||
MCUSR = 0 ;
|
||
WDTCR = 0 ;
|
||
|
||
}
|
||
|
||
/***********************************************************************/
|
||
|
||
static void Init_WatchDogTimer (void)
|
||
{
|
||
/*
|
||
Timed sequence to initialize watchdog timer
|
||
for the given mode set in gtimeout variable
|
||
Cross calls during maximum optimization can
|
||
cause more than 4 cycles delay between change
|
||
enable for WDT and setting values
|
||
*/
|
||
wdt_reset();
|
||
WDTCR = (1 << WDCE) | ( 1 << WDE ) ;
|
||
WDTCR = ( 1 << WDE ) | gtimeout ;
|
||
}
|
||
|
||
|
||
/***********************************************************************/
|
||
NOINLINE void set_clock( uint8_t speed )
|
||
{
|
||
volatile uint8_t *ptr ;
|
||
ptr = &CLKPR ;
|
||
*ptr = 0x80 ;
|
||
*ptr = speed ;
|
||
}
|
||
|
||
/***********************************************************************/
|
||
// Main Starts from here
|
||
void main (void)
|
||
{
|
||
|
||
USI_TWI_SLAVE_Init();
|
||
//__enable_interrupt();
|
||
|
||
Init_WatchDogTimer() ;
|
||
|
||
/*RTC 32.768kHz, div 128 */
|
||
{
|
||
PRR = 0x39 ;
|
||
TCCR0A = 0 ;
|
||
TCCR0B = 5 ; // Divide/128
|
||
ASSR = 0x20 ; // Async mode
|
||
while((ASSR & 0b00011011) != 0x00);/*Wait until TCNT0, OCR0A, TCCR0A and TCCR0B updated*/
|
||
TIFR0 = 0x01;/*Clear T0 int flag*/
|
||
|
||
}
|
||
t_time *p = &Time ;
|
||
FORCE_INDIRECT(p) ;
|
||
|
||
p->second = 5 ;
|
||
p->minute = 6 ;
|
||
p->hour = 16 ;
|
||
p->date= 23 ;
|
||
p->month = 9 ;
|
||
p->year = 2012 ;
|
||
|
||
bufferPtr = DataBuffer ;
|
||
|
||
T_offset = boot_signature_byte_get( TSOFFSET ) ;
|
||
T_gain = boot_signature_byte_get( TSGAIN ) ;
|
||
T_mult = 32768U / T_gain ;
|
||
|
||
enableAdc() ;
|
||
for(;;)
|
||
{
|
||
USI_TWI_SLAVE_ReadAndProcessPacket() ;
|
||
}
|
||
}
|
||
|
||
|
||
// Enable ADC
|
||
void enableAdc()
|
||
{
|
||
cbi( PRR, PRADC ) ; // Power the ADC
|
||
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); // set ADC prescaler to , 8MHz / 64 = 125kHz
|
||
}
|
||
|
||
// Disable ADC
|
||
void disableAdc()
|
||
{
|
||
ADCSRA = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) ; // set ADC prescaler to , 8MHz / 256 = 30kHz
|
||
sbi( PRR, PRADC ) ; // Power Down the ADC
|
||
}
|
||
|