Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
blackson
PostPosted: Jun 02, 2012 - 04:37 PM
Wannabe


Joined: Oct 06, 2008
Posts: 70


I am testing a board I made for the AT32UC3A0512. Some of it works fine. I can program it via JTAG. But I am having a problem with the TWI. It initializes but hangs when writing and reading. I have 10K pullups on the lines. I used that value because that is what is on the EVK1100 schematic. Any idea what the problem might be?
 
 View user's profile Send private message  
Reply with quote Back to top
larryvc
PostPosted: Jun 02, 2012 - 04:54 PM
Raving lunatic


Joined: Dec 06, 2007
Posts: 2512
Location: Redmond, WA USA

blackson wrote:
Any idea what the problem might be?

I lent my crystal ball to a guy named Samperi. Wink

You will definitely get a better answer if you show the code and the schematic. Smile

_________________
Larry

Those afraid to embrace the future will quickly fade into the past. - larryvc
 
 View user's profile Send private message  
Reply with quote Back to top
blackson
PostPosted: Jun 02, 2012 - 05:12 PM
Wannabe


Joined: Oct 06, 2008
Posts: 70


Okay. Here are main.c, the schematics, and the board. I am afraid the schematic is a little ugly.
 
 View user's profile Send private message  
Reply with quote Back to top
blackson
PostPosted: Jun 06, 2012 - 01:17 PM
Wannabe


Joined: Oct 06, 2008
Posts: 70


I think I might have found the problem. I use twi_master_read to do single byte reads. The data sheet says that "when a single data byte read is performed, with or without internal address (IADR), the START and STOP bits must be set at the same time." (Page 226; see also the flowcharts on 232 and 232.) But the code for twi_master_read seems to assume the read will always be for multiple bytes:
Code:

// Enable master transfer
   twi->cr =  AVR32_TWI_CR_MSEN_MASK;
 
   // Send start condition
   twi->cr = AVR32_TWI_START_MASK;
 
   // only one byte to receive
   if(twi_rx_nb_bytes == 1)
  {
     // set stop bit
    twi->cr = AVR32_TWI_STOP_MASK;
  }

  // mask NACK and RXRDY interrupts
   twi_it_mask = AVR32_TWI_IER_NACK_MASK | AVR32_TWI_IER_RXRDY_MASK;

  // update IMR through IER
  twi->ier = twi_it_mask;
 
   // get data
   while( twi_is_busy() ) {
     cpu_relax();
   }

Am I right about twi_master_read, that it can't do a single byte read? If so, is there some other function in the TWI module I should use? I didn't see one.
 
 View user's profile Send private message  
Reply with quote Back to top
david.prentice
PostPosted: Jun 06, 2012 - 03:33 PM
10k+ Postman


Joined: Feb 12, 2005
Posts: 16544
Location: Wormshill, England

Quote:
int twi_master_read ( volatile avr32_twi_t * twi,
const twi_package_t * package
)

You set up the twi_package_t structure accordingly.
Quote:
uint8_t addr [3]
TWI address/commands to issue to the other chip (node).

int addr_length
Length of the TWI data address segment (1-3 bytes).

void * buffer
Where to find the data to be written.

char chip
TWI chip address to communicate with.

unsigned int length
How many bytes do we want to write.


So if you want to read one byte "at current address", you would have
Code:
twi_package_t package = { NULL, 0, &ch, SLAVE, 1};


Now I have never used ASF nor AVR32. So this is speculation on my part. Note that you don't even say what hardware chip you are using. So I have no idea whether you need to set up the "current read address".

No, I have not bothered to read the ASF source code. I would just follow the documented API and see how it behaves.

David.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
blackson
PostPosted: Jun 06, 2012 - 10:55 PM
Wannabe


Joined: Oct 06, 2008
Posts: 70


Thanks for the suggestion. I will do some experimenting. I just have not had time yet, and I thought there must be people who have used the TWI module in the ASF to do single byte reads. Also, the chip I am using is the AT32UC3A0512, which I mentioned in the first post.
 
 View user's profile Send private message  
Reply with quote Back to top
E_forge
PostPosted: Jul 17, 2012 - 12:52 PM
Rookie


Joined: Oct 20, 2011
Posts: 23


Having similar TWI problems here. The MCU is UC3C1512, we are trying to use TWIM0 and ASF.

The problem with unmodified ASF is that it freezes after a slave device sends ACK. We have tried to remove all software wait loops from ASF source that leave the controller to sleep mode, but the problem seems to be that although the ASF code is interrupt driven, the TWI master interrupt never actually gets called. We have checked the bus with digital scope and it seems that if no slave or a slave with wrong address is on the line (thus no ACK after ADRS byte), the code finishes normally, but if we get the ACK byte from slave, the interrupt never gets to the point of sending data, leaving SCK low and the MCU freezes.

We also have another problem: We have several other interrupt requests working simultaneously and thus would need a NON-interrupt driven TWI code (it is the main thing the MCU is doing at the moment, and can handle other short interrupts if needed). However, It is not immediately obvious from datasheet if this is even possible (should be, at least in 8-bit AVRs this works just fine by software-polling flags). We tried to write our own code, making it much simpler than the ASF example (ASF has poor documentation, it uses a lot of complicated data types to do it's job and seems to only work if and only if it is the only code running on the AVR). We can't get our code to work however, although we tried to follow the datasheet instructions. Is there any ready code for this? We basically only need to send one byte per slave to a TWI bus, but the complicated ASF code doesn't seem to work for our purpose.
 
 View user's profile Send private message  
Reply with quote Back to top
jschiavoni
PostPosted: Apr 18, 2013 - 04:27 PM
Wannabe


Joined: Feb 14, 2008
Posts: 51
Location: Buenos Aires

Hi, I have the same problem, and fix it changing the loop that wait for a queue of FreeRtos.

Read function:

Code:
#ifdef FREERTOS_USED
int twi_master_read(volatile avr32_twi_t *twi,
               const twi_package_t *package, uint32_t timeout )
#else
int twi_master_read(volatile avr32_twi_t *twi,
               const twi_package_t *package )
#endif

{
   // check argument
   if (package->length == 0) {
      return TWI_INVALID_ARGUMENT;
   }

#ifdef FREERTOS_USED
   if( twi_wait_while_busy( timeout ) == TWI_TIMEOUT )
   {
      return TWI_TIMEOUT;
   }
#else
   while (twi_is_busy()) {
      cpu_relax();
   };
#endif

   twi_nack = false;
   twi_busy = true;

   // set read mode, slave address and 3 internal address byte length
   twi->mmr = (package->chip << AVR32_TWI_MMR_DADR_OFFSET) |
         ((package->addr_length << AVR32_TWI_MMR_IADRSZ_OFFSET) & AVR32_TWI_MMR_IADRSZ_MASK) |
         (1 << AVR32_TWI_MMR_MREAD_OFFSET);

   // Set pointer to TWIM instance for IT
   twi_inst = twi;

   // set internal address for remote chip
   twi->iadr = twi_mk_addr(package->addr, package->addr_length);

   // get a pointer to applicative data
   twi_rx_data = package->buffer;

   // get a copy of nb bytes to read
   twi_rx_nb_bytes = package->length;

   // Enable master transfer
   twi->cr =  AVR32_TWI_CR_MSEN_MASK;

   // Send start condition
   twi->cr = AVR32_TWI_START_MASK;

   // only one byte to receive
   if (twi_rx_nb_bytes == 1) {
      // set stop bit
      twi->cr = AVR32_TWI_STOP_MASK;
   }

   // mask NACK and RXRDY interrupts
   twi_it_mask = AVR32_TWI_IER_NACK_MASK | AVR32_TWI_IER_RXRDY_MASK;

   // update IMR through IER
   twi->ier = twi_it_mask;

#ifdef FREERTOS_USED
   if( twi_wait_while_busy( timeout ) == TWI_TIMEOUT )
   {
      // Disable master transfer
      twi->cr =  AVR32_TWI_CR_MSDIS_MASK;
      return TWI_TIMEOUT;
   }
#else
   // get data
   while (twi_is_busy()) {
      cpu_relax();
   }
#endif

   // Disable master transfer
   twi->cr =  AVR32_TWI_CR_MSDIS_MASK;

   if (twi_nack) {
      return TWI_RECEIVE_NACK;
   }

   return TWI_SUCCESS;
}


Wait function:
Code:

#ifdef FREERTOS_USED
static int twi_wait_while_busy( uint32_t timeout )
{
int     ret_val = TWI_SUCCESS;
uint8_t data;

   if( twi_is_busy() )
   {
      if( pdTRUE == xQueueReceive( twi_queue, &data, timeout ) )
      {
         if( twi_is_busy() )
         {
            ret_val = TWI_BUSY;
         }
      }
      else
      {
         ret_val = TWI_TIMEOUT;
      }
   }

   return ret_val; ;
}
#endif


Irq Service Routine:
Code:

#ifdef FREERTOS_USED
   //! Semaphore for wait complete.
   static xQueueHandle twi_queue = 0;
   static int twi_wait_while_busy( uint32_t timeout );
#endif


#define CONF_TWI_IRQ_LINE          AVR32_TWI_IRQ
#define CONF_TWI_IRQ_GROUP         AVR32_TWI_IRQ_GROUP

#ifdef FREERTOS_USED
__attribute__((__noinline__)) static portBASE_TYPE    twi_master_interrupt_non_naked_behaviour( void );

__attribute__((naked)) void twi_master_interrupt_handler( void )
{
   /**
    * This ISR can cause a context switch, so the first statement must be a
    * call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any
    * variable declarations.
    */
   portENTER_SWITCHING_ISR();
   twi_master_interrupt_non_naked_behaviour();
   portEXIT_SWITCHING_ISR();
}
#endif

/*! \brief TWI interrupt handler.
 */
#ifndef FREERTOS_USED
ISR(twi_master_interrupt_handler, CONF_TWI_IRQ_GROUP, CONF_TWI_IRQ_LEVEL)
{
#else
__attribute__((__noinline__))
static portBASE_TYPE twi_master_interrupt_non_naked_behaviour( void )
{
uint32_t       new_cmd                 = 0;
portBASE_TYPE    higher_prioritytask_woken = pdFALSE;
#endif

   // get masked status register value
   int status = twi_inst->sr & twi_it_mask;

   // this is a NACK
   if (status & AVR32_TWI_SR_NACK_MASK) {
      goto nack;
   }
   // this is a RXRDY
   else if (status & AVR32_TWI_SR_RXRDY_MASK) {
      // get data from Receive Holding Register
      *twi_rx_data = twi_inst->rhr;
      twi_rx_data++;
      // last byte to receive
      if (--twi_rx_nb_bytes == 1) {
         // set stop bit
         twi_inst->cr = AVR32_TWI_STOP_MASK;
      }
      // receive complete
      if (twi_rx_nb_bytes == 0) {
         // finish the receive operation
         goto complete;
      }
   }
   // this is a TXRDY
   else if (status & AVR32_TWI_SR_TXRDY_MASK) {
      // decrease transmitted bytes number
      twi_tx_nb_bytes--;
      // no more bytes to transmit
      if (twi_tx_nb_bytes <= 0) {
         // enable TXCOMP IT and unmask all others IT
         twi_it_mask = AVR32_TWI_IER_TXCOMP_MASK;
         twi_inst->idr = ~0UL;
         twi_inst->ier = twi_it_mask;
      } else {
         // put the byte in the Transmit Holding Register
         twi_inst->thr = *twi_tx_data++;
      }
   }
   // this is a TXCOMP
   else if (status & AVR32_TWI_SR_TXCOMP_MASK) {
      // finish the transmit operation
      goto complete;
   }

#ifdef FREERTOS_USED
   return higher_prioritytask_woken;
#else
   return;
#endif

nack:
   twi_nack = true;

complete:
   // disable all interrupts
   twi_inst->idr = ~0UL;
   twi_inst->sr;
   twi_busy = false;

#ifdef FREERTOS_USED
   /**
    * Because FreeRTOS is not supposed to run with nested interrupts,
    * put all OS calls in a critical section when are made in a IRQ.
    */
   portENTER_CRITICAL();
   xQueueSendFromISR( twi_queue,
                  &new_cmd,
                  &higher_prioritytask_woken );
   portEXIT_CRITICAL();

   /**
    * The return value will be used by portEXIT_SWITCHING_ISR()
    * to know if it should perform a vTaskSwitchContext().
    */
   return higher_prioritytask_woken;
#else
   return;
#endif

}





 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits