roboforum.ru

Технический форум по робототехнике.

USI ATtiny2313 в режиме SPI

Программирование микроконтроллеров AVR, PIC, ARM.
Разработка и изготовление печатных плат для модулей.

USI ATtiny2313 в режиме SPI

Сообщение Карлсон » 10 янв 2007, 01:00

Мне необходимо запустить USI у тиньки в качестве SPI.
В апноуте AVR319 все расписано.
даже код есть. под IAR.

вот драйвер:
Код: Выделить всёРазвернуть
// This file has been prepared for Doxygen automatic documentation generation.
/*! \file ********************************************************************
*
* Atmel Corporation
*
* \li File:               spi_via_usi_driver.c
* \li Compiler:           IAR EWAAVR 3.10c
* \li Support mail:       avr@atmel.com
*
* \li Supported devices:  All devices with Universal Serial Interface (USI)
*                         capabilities can be used.
*                         The example is written for ATmega169.
*
* \li AppNote:            AVR319 - Using the USI module for SPI communication.
*
* \li Description:        Example on how to use the USI module for communicating
*                         with SPI compatible devices. The functions and variables
*                         prefixed 'spiX_' can be renamed to be able to use several
*                         spi drivers (using different interfaces) with similar names.
*                         Some basic SPI knowledge is assumed.
*
*                         $Revision: 1.4 $
*                         $Date: Monday, September 13, 2004 12:08:54 UTC $
****************************************************************************/
#include <ioavr.h>
#include <inavr.h>



/* USI port and pin definitions.
*/
#define USI_OUT_REG   PORTE   //!< USI port output register.
#define USI_IN_REG   PINE   //!< USI port input register.
#define USI_DIR_REG   DDRE   //!< USI port direction register.
#define USI_CLOCK_PIN   PE4   //!< USI clock I/O pin.
#define USI_DATAIN_PIN   PE5   //!< USI data input pin.
#define USI_DATAOUT_PIN   PE6   //!< USI data output pin.




/*  Speed configuration:
*  Bits per second = CPUSPEED / PRESCALER / (COMPAREVALUE+1) / 2.
*  Maximum = CPUSPEED / 64.
*/
#define TC0_PRESCALER_VALUE 256   //!< Must be 1, 8, 64, 256 or 1024.
#define TC0_COMPARE_VALUE   1   //!< Must be 0 to 255. Minimum 31 with prescaler CLK/1.




/*  Prescaler value converted to bit settings.
*/
#if TC0_PRESCALER_VALUE == 1
   #define TC0_PS_SETTING (1<<CS00)
#elif TC0_PRESCALER_VALUE == 8
   #define TC0_PS_SETTING (1<<CS01)
#elif TC0_PRESCALER_VALUE == 64
   #define TC0_PS_SETTING (1<<CS01)|(1<<CS00)
#elif TC0_PRESCALER_VALUE == 256
   #define TC0_PS_SETTING (1<<CS02)
#elif TC0_PRESCALER_VALUE == 1024
   #define TC0_PS_SETTING (1<<CS02)|(1<<CS00)
#else
   #error Invalid T/C0 prescaler setting.
#endif



/*! \brief  Data input register buffer.
*
*  Incoming bytes are stored in this byte until the next transfer is complete.
*  This byte can be used the same way as the SPI data register in the native
*  SPI module, which means that the byte must be read before the next transfer
*  completes and overwrites the current value.
*/
unsigned char storedUSIDR;



/*! \brief  Driver status bit structure.
*
*  This struct contains status flags for the driver.
*  The flags have the same meaning as the corresponding status flags
*  for the native SPI module. The flags should not be changed by the user.
*  The driver takes care of updating the flags when required.
*/
struct usidriverStatus_t {
   unsigned char masterMode : 1;       //!< True if in master mode.
   unsigned char transferComplete : 1; //!< True when transfer completed.
   unsigned char writeCollision : 1;   //!< True if put attempted during transfer.
};

volatile struct usidriverStatus_t spiX_status; //!< The driver status bits.



/*! \brief  Timer/Counter 0 Compare Match Interrupt handler.
*
*  This interrupt handler is only enabled when transferring data
*  in master mode. It toggles the USI clock pin, i.e. two interrupts
*  results in one clock period on the clock pin and for the USI counter.
*/
#pragma vector=TIMER0_COMP_vect
__interrupt void timer0comp_handler()
{
   USICR |= (1<<USITC);   // Toggle clock output pin.
}



/*! \brief  USI Timer Overflow Interrupt handler.
*
*  This handler disables the compare match interrupt if in master mode.
*  When the USI counter overflows, a byte has been transferred, and we
*  have to stop the timer tick.
*  For all modes the USIDR contents are stored and flags are updated.
*/
#pragma vector=USI_OVF_vect
__interrupt void usiovf_handler()
{
   // Master must now disable the compare match interrupt
   // to prevent more USI counter clocks.
   if( spiX_status.masterMode == 1 ) {
      TIMSK0 &= ~(1<<OCIE0A);
   }
   
   // Update flags and clear USI counter
   USISR = (1<<USIOIF);
   spiX_status.transferComplete = 1;

   // Copy USIDR to buffer to prevent overwrite on next transfer.
   storedUSIDR = USIDR;
}



/*! \brief  Initialize USI as SPI master.
*
*  This function sets up all pin directions and module configurations.
*  Use this function initially or when changing from slave to master mode.
*  Note that the stored USIDR value is cleared.
*
*  \param spi_mode  Required SPI mode, must be 0 or 1.
*/
void spiX_initmaster( char spi_mode )
{
   // Configure port directions.
   USI_DIR_REG |= (1<<USI_DATAOUT_PIN) | (1<<USI_CLOCK_PIN); // Outputs.
   USI_DIR_REG &= ~(1<<USI_DATAIN_PIN);                      // Inputs.
   USI_OUT_REG |= (1<<USI_DATAIN_PIN);                       // Pull-ups.
   
   // Configure USI to 3-wire master mode with overflow interrupt.
   USICR = (1<<USIOIE) | (1<<USIWM0) |
           (1<<USICS1) | (spi_mode<<USICS0) |
           (1<<USICLK);

   // Enable 'Clear Timer on Compare match' and init prescaler.
   TCCR0A = (1<<WGM01) | TC0_PS_SETTING;
   
   // Init Output Compare Register.
   OCR0A = TC0_COMPARE_VALUE;
   
   // Init driver status register.
   spiX_status.masterMode       = 1;
   spiX_status.transferComplete = 0;
   spiX_status.writeCollision   = 0;
   
   storedUSIDR = 0;
}



/*! \brief  Initialize USI as SPI slave.
*
*  This function sets up all pin directions and module configurations.
*  Use this function initially or when changing from master to slave mode.
*  Note that the stored USIDR value is cleared.
*
*  \param spi_mode  Required SPI mode, must be 0 or 1.
*/
void spiX_initslave( char spi_mode )
{
   // Configure port directions.
   USI_DIR_REG |= (1<<USI_DATAOUT_PIN);                      // Outputs.
   USI_DIR_REG &= ~(1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN); // Inputs.
   USI_OUT_REG |= (1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN);  // Pull-ups.
   
   // Configure USI to 3-wire slave mode with overflow interrupt.
   USICR = (1<<USIOIE) | (1<<USIWM0) |
           (1<<USICS1) | (spi_mode<<USICS0);
   
   // Init driver status register.
   spiX_status.masterMode       = 0;
   spiX_status.transferComplete = 0;
   spiX_status.writeCollision   = 0;
   
   storedUSIDR = 0;
}



/*! \brief  Put one byte on bus.
*
*  Use this function like you would write to the SPDR register in the native SPI module.
*  Calling this function in master mode starts a transfer, while in slave mode, a
*  byte will be prepared for the next transfer initiated by the master device.
*  If a transfer is in progress, this function will set the write collision flag
*  and return without altering the data registers.
*
*  \returns  0 if a write collision occurred, 1 otherwise.
*/
char spiX_put( unsigned char val )
{
   // Check if transmission in progress,
   // i.e. USI counter unequal to zero.
   if( (USISR & 0x0F) != 0 ) {
      // Indicate write collision and return.
      spiX_status.writeCollision = 1;
      return;
   }
   
   // Reinit flags.
   spiX_status.transferComplete = 0;
   spiX_status.writeCollision = 0;

   // Put data in USI data register.
   USIDR = val;
   
   // Master should now enable compare match interrupts.
   if( spiX_status.masterMode == 1 ) {
      TIFR0 |= (1<<OCF0A);   // Clear compare match flag.
      TIMSK0 |= (1<<OCIE0A); // Enable compare match interrupt.
   }

   if( spiX_status.writeCollision == 0 ) return 1;
   return 0;
}



/*! \brief  Get one byte from bus.
*
*  This function only returns the previous stored USIDR value.
*  The transfer complete flag is not checked. Use this function
*  like you would read from the SPDR register in the native SPI module.
*/
unsigned char spiX_get()
{
   return storedUSIDR;
}



/*! \brief  Wait for transfer to complete.
*
*  This function waits until the transfer complete flag is set.
*  Use this function like you would wait for the native SPI interrupt flag.
*/
void spiX_wait()
{
   do {} while( spiX_status.transferComplete == 0 );
}



// end of file


вот пример использования:

Код: Выделить всёРазвернуть
/* Test application for the SPI-via-USI-driver. */

#include "spi_via_usi_driver.c"



#define SPIMODE 0   // Sample on leading _rising_ edge, setup on trailing _falling_ edge.
//#define SPIMODE 1   // Sample on leading _falling_ edge, setup on trailing _rising_ edge.



void main()
{
   unsigned char val = 0;      // Temp value to send.
   DDRB = 0xFF;         // Set PORTB to all output.
//   spiX_initmaster(SPIMODE);   // Init SPI driver as master.
   spiX_initslave(SPIMODE);   // Init SPI driver as slave.
   __enable_interrupt();      // Must do this to make driver work.
   do {
      spiX_put( val++ );   // Send temp value to SPI and increment,
      spiX_wait();      // wait for transmission to finish
      PORTB = spiX_get();   // and finally put result on PORTB.
   } while(1);         // Loop forever...
}


Мне хотелось бы это дело переписать под CodeVision.
Вот что у меня получается:

Код: Выделить всёРазвернуть
#include <tiny2313.h>

// Declare your global variables here

void Init(void){
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port A initialization
// Func2=In Func1=In Func0=In
// State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=In Func6=Out Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=0 State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0xC0;

// Port D initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x80;
TCCR0B=0x01;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
GIMSK=0x00;
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x03;

// Universal Serial Interface initialization
// Mode: Three Wire (SPI)
// Clock source: Reg.=ext. pos. edge, Cnt.=USITC
// USI Counter Overflow Interrupt: Off
//USICR=0x23;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
}

/* USI port and pin definitions.
*/
#define USI_OUT_REG   PORTB   //!< USI port output register.
#define USI_IN_REG   PINB   //!< USI port input register.
#define USI_DIR_REG   DDRB   //!< USI port direction register.
#define USI_CLOCK_PIN   PORTB.7   //!< USI clock I/O pin.
#define USI_DATAIN_PIN   PORTB.5   //!< USI data input pin.
#define USI_DATAOUT_PIN   PORTB.6   //!< USI data output pin.




/*  Speed configuration:
*  Bits per second = CPUSPEED / PRESCALER / (COMPAREVALUE+1) / 2.
*  Maximum = CPUSPEED / 64.
*/
#define TC0_PRESCALER_VALUE 256   //!< Must be 1, 8, 64, 256 or 1024.
#define TC0_COMPARE_VALUE   1   //!< Must be 0 to 255. Minimum 31 with prescaler CLK/1.




/*  Prescaler value converted to bit settings.
*/
#if TC0_PRESCALER_VALUE == 1
   #define TC0_PS_SETTING (TCCR0B+1)
#elif TC0_PRESCALER_VALUE == 8
   #define TC0_PS_SETTING (TCCR0B+2)
#elif TC0_PRESCALER_VALUE == 64
   #define TC0_PS_SETTING (TCCR0B+2)|(TCCR0B+1)
#elif TC0_PRESCALER_VALUE == 256
   #define TC0_PS_SETTING (TCCR0B+4)
#elif TC0_PRESCALER_VALUE == 1024
   #define TC0_PS_SETTING (TCCR0B+4)|(TCCR0B+1)
#else
   #error Invalid T/C0 prescaler setting.
#endif



/*! \brief  Data input register buffer.
*
*  Incoming bytes are stored in this byte until the next transfer is complete.
*  This byte can be used the same way as the SPI data register in the native
*  SPI module, which means that the byte must be read before the next transfer
*  completes and overwrites the current value.
*/
unsigned char storedUSIDR;



/*! \brief  Driver status bit structure.
*
*  This struct contains status flags for the driver.
*  The flags have the same meaning as the corresponding status flags
*  for the native SPI module. The flags should not be changed by the user.
*  The driver takes care of updating the flags when required.
*/
struct usidriverStatus_t {
   unsigned char masterMode : 1;       //!< True if in master mode.
   unsigned char transferComplete : 1; //!< True when transfer completed.
   unsigned char writeCollision : 1;   //!< True if put attempted during transfer.
};

volatile struct usidriverStatus_t spiX_status; //!< The driver status bits.



/*! \brief  Timer/Counter 0 Compare Match Interrupt handler.
*
*  This interrupt handler is only enabled when transferring data
*  in master mode. It toggles the USI clock pin, i.e. two interrupts
*  results in one clock period on the clock pin and for the USI counter.
*/
interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
// Place your code here
   USICR |= (1<<USICR.0);   // Toggle clock output pin.
}



/*! \brief  USI Timer Overflow Interrupt handler.
*
*  This handler disables the compare match interrupt if in master mode.
*  When the USI counter overflows, a byte has been transferred, and we
*  have to stop the timer tick.
*  For all modes the USIDR contents are stored and flags are updated.
*/
interrupt [USI_OVERFLOW] void usiovf_handler()
{
   // Master must now disable the compare match interrupt
   // to prevent more USI counter clocks.
   if( spiX_status.masterMode == 1 ) {
      TIMSK &= ~(TIMSK+1);
   }
   
   // Update flags and clear USI counter
   USISR = (1<<USISR.6);
   spiX_status.transferComplete = 1;

   // Copy USIDR to buffer to prevent overwrite on next transfer.
   storedUSIDR = USIDR;
}



/*! \brief  Initialize USI as SPI master.
*
*  This function sets up all pin directions and module configurations.
*  Use this function initially or when changing from slave to master mode.
*  Note that the stored USIDR value is cleared.
*
*  \param spi_mode  Required SPI mode, must be 0 or 1.
*/
void spiX_initmaster( char spi_mode )
{
   // Configure port directions.
   USI_DIR_REG |= (1<<USI_DATAOUT_PIN) | (1<<USI_CLOCK_PIN); // Outputs.
   USI_DIR_REG &= ~(1<<USI_DATAIN_PIN);                      // Inputs.
   USI_OUT_REG |= (1<<USI_DATAIN_PIN);                       // Pull-ups.
   
   // Configure USI to 3-wire master mode with overflow interrupt.
   USICR = (1<<USICR.6) | (1<<USICR.4) |
           (1<<USICR.3) | (spi_mode<<USICR.2) |
           (1<<USISR.1);

   // Enable 'Clear Timer on Compare match' and init prescaler.
   TCCR0A = TCCR0A+2 | TC0_PS_SETTING;
   
   // Init Output Compare Register.
   OCR0A = TC0_COMPARE_VALUE;
   
   // Init driver status register.
   spiX_status.masterMode       = 1;
   spiX_status.transferComplete = 0;
   spiX_status.writeCollision   = 0;
   
   storedUSIDR = 0;
}



/*! \brief  Initialize USI as SPI slave.
*
*  This function sets up all pin directions and module configurations.
*  Use this function initially or when changing from master to slave mode.
*  Note that the stored USIDR value is cleared.
*
*  \param spi_mode  Required SPI mode, must be 0 or 1.
*/
void spiX_initslave( char spi_mode )
{
   // Configure port directions.
   USI_DIR_REG |= (1<<USI_DATAOUT_PIN);                      // Outputs.
   USI_DIR_REG &= ~(1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN); // Inputs.
   USI_OUT_REG |= (1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN);  // Pull-ups.
   
   // Configure USI to 3-wire slave mode with overflow interrupt.
   USICR = (1<<USISR.6) | (1<<USICR.4) |
           (1<<USICR.3) | (spi_mode<<USICR.2);
   
   // Init driver status register.
   spiX_status.masterMode       = 0;
   spiX_status.transferComplete = 0;
   spiX_status.writeCollision   = 0;
   
   storedUSIDR = 0;
}



/*! \brief  Put one byte on bus.
*
*  Use this function like you would write to the SPDR register in the native SPI module.
*  Calling this function in master mode starts a transfer, while in slave mode, a
*  byte will be prepared for the next transfer initiated by the master device.
*  If a transfer is in progress, this function will set the write collision flag
*  and return without altering the data registers.
*
*  \returns  0 if a write collision occurred, 1 otherwise.
*/
char spiX_put( unsigned char val )
{
   // Check if transmission in progress,
   // i.e. USI counter unequal to zero.
   if( (USISR & 0x0F) != 0 ) {
      // Indicate write collision and return.
      spiX_status.writeCollision = 1;
      return;
   }
   
   // Reinit flags.
   spiX_status.transferComplete = 0;
   spiX_status.writeCollision = 0;

   // Put data in USI data register.
   USIDR = val;
   
   // Master should now enable compare match interrupts.
   if( spiX_status.masterMode == 1 ) {
      TIFR |= TIFR+1;   // Clear compare match flag.
      TIMSK |= TIMSK+1; // Enable compare match interrupt.
   }

   if( spiX_status.writeCollision == 0 ) return 1;
   return 0;
}



/*! \brief  Get one byte from bus.
*
*  This function only returns the previous stored USIDR value.
*  The transfer complete flag is not checked. Use this function
*  like you would read from the SPDR register in the native SPI module.
*/
unsigned char spiX_get()
{
   return storedUSIDR;
}



/*! \brief  Wait for transfer to complete.
*
*  This function waits until the transfer complete flag is set.
*  Use this function like you would wait for the native SPI interrupt flag.
*/
void spiX_wait()
{
   do {} while( spiX_status.transferComplete == 0 );
}



// end of file

#define SPIMODE 0   // Sample on leading _rising_ edge, setup on trailing _falling_ edge.
//#define SPIMODE 1   // Sample on leading _falling_ edge, setup on trailing _rising_ edge.

void main(void){
unsigned char val = 0;   
Init();
spiX_initmaster(SPIMODE);   // Init SPI driver as master.
//   spiX_initslave(SPIMODE);   // Init SPI driver as slave.
while(1){
spiX_put(val++);
spiX_wait();
};      
}


естественно не работает.
PORTB.7 все время в единице.
очевидно, я где-то что-то не так понимаю и соответственно пишу неправильно.
кто-нибудь поможет с этим разобраться?
Аватара пользователя
Карлсон
 
Сообщения: 114
Зарегистрирован: 30 окт 2005, 13:10
Откуда: Москва

Сообщение avr123.nm.ru » 10 янв 2007, 10:46

всегда приятно работать с МК не поддерживаемыми нормальными симуляторами - сразу видно что и где не так...  остается лишь подправить.

а можно взять МК поддерживаемый симуляторами...  но это уже другая история.
Аватара пользователя
avr123.nm.ru
отсылающий читать курс
 
Сообщения: 14195
Зарегистрирован: 06 ноя 2005, 04:18
Откуда: Москва
Предупреждения: -8

Сообщение Карлсон » 10 янв 2007, 17:19

ну например?
посоветуйте замену!
меги не подходят, т.к. слишком большие - восьмая еще куда ни шло, но пока что на ней у меня не получается сконтачиться с цапом.
90s - дык атмел их сам не рекомендует в новых разработках.
Аватара пользователя
Карлсон
 
Сообщения: 114
Зарегистрирован: 30 окт 2005, 13:10
Откуда: Москва


Вернуться в Микроконтроллеры

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 0

cron