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
mjordan
PostPosted: Jan 26, 2012 - 04:18 PM
Wannabe


Joined: May 20, 2008
Posts: 67


The ASF twim.c code seems to only support a single twi master since it uses a global twim_inst variable for the interrupt routine. I'm assuming there are no hardware limitations for running all three twi ports simultaneously as master, correct?


Last edited by mjordan on Jan 26, 2012 - 09:37 PM; edited 1 time in total
 
 View user's profile Send private message  
Reply with quote Back to top
danicampora
PostPosted: Jan 26, 2012 - 04:26 PM
Hangaround


Joined: Oct 10, 2007
Posts: 395
Location: Valls, Spain

There are not hardware limitations. The driver is hardcoded to use the TWIM0 module. You just need to modify it to work with multiple TWI ports. I've done it and it works as it should.

_________________
Daniel Campora
http://www.lear.com
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Jan 26, 2012 - 06:33 PM
Moderator


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway

Please file a bug report so we can take a look at it and schedule it for enhancement.

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
mjordan
PostPosted: Jan 26, 2012 - 07:39 PM
Wannabe


Joined: May 20, 2008
Posts: 67


abcminiuser wrote:
Please file a bug report so we can take a look at it and schedule it for enhancement.

- Dean Twisted Evil


I sent a ticket in to avr32@atmel.com - is that sufficient or is there an official bug reporting mechanism?
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jan 26, 2012 - 07:51 PM
Moderator


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway

Darn, I thought the link text in my post above would be easy to spot.

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
mjordan
PostPosted: Jan 26, 2012 - 09:36 PM
Wannabe


Joined: May 20, 2008
Posts: 67


mjordan wrote:
abcminiuser wrote:
Please file a bug report so we can take a look at it and schedule it for enhancement.

- Dean Twisted Evil


I sent a ticket in to avr32@atmel.com - is that sufficient or is there an official bug reporting mechanism?


Totally did NOT see it. The light blue is too light Smile

Bug submitted: http://asf.atmel.com/bugzilla/show_bug.cgi?id=1693
 
 View user's profile Send private message  
Reply with quote Back to top
Theguigz
PostPosted: Jun 15, 2012 - 06:33 AM
Newbie


Joined: Mar 17, 2011
Posts: 14
Location: Montreal

Sorry if i post here, but i haven't found any other post for TWIM modules for UC3C chip. I would like to know why there is no function in the asf that can use the TWI without having some blocking code.

I am using those chips in UAV and we cannot have that kind of while "wait for device to finish".

Is there a way to modify the existing code to permit this easily ?

_________________
Guillaume Charland
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Jun 15, 2012 - 08:21 AM
Moderator


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway

I was toying around with this on my spare time - attached is a preliminary example and not fully tested AVR32 TWIM driver that supports asynchronous callbacks.

Use it as an example only since I can't guarantee anything about it -- if it works for you great, but I'd rather you use it as a reference for your own fully tested driver.

Code:
#include "twim.h"

#if UC3A3
#       if !defined(AVR32_TWIM0_GROUP)
#               define AVR32_TWIM0_GROUP         11
#       endif
#       if !defined(AVR32_TWIM1_GROUP)
#               define AVR32_TWIM1_GROUP         12
#       endif
#endif

#if UC3C
#       if !defined(AVR32_TWIM0_GROUP)
#               define AVR32_TWIM0_GROUP         25
#       endif
#       if !defined(AVR32_TWIM1_GROUP)
#               define AVR32_TWIM1_GROUP         26
#       endif
#       if !defined(AVR32_TWIM2_GROUP)
#               define AVR32_TWIM2_GROUP         45
#       endif
#endif

#if UC3D
#       if !defined(AVR32_TWIM_GROUP)
#                       define AVR32_TWIM_GROUP         10
#       endif
#endif

#if UC3L
#       if !defined(AVR32_TWIM0_GROUP)
#               define AVR32_TWIM0_GROUP         20
#       endif
#       if !defined(AVR32_TWIM1_GROUP)
#               define AVR32_TWIM1_GROUP         21
#       endif
#endif

/**
 * \internal
 *
 * \brief TWI master mode software instance struct.
 */
struct twi_master_instance {
        /*! Asynchronous callback function */
        twi_master_callback_t callback;
       
        /*! Indicates if the transfer should be a read or a write. */
        bool read;

        /*! Current logical status of the bus. */
        volatile status_code_t status;

        /*! Current package being transferred on the bus. */
        const twi_package_t *current_transfer;

        /*! Number of internal address bytes sent to the slave on the bus. */
        uint8_t sent_address_bytes;

        /*! Number of transferred bytes transferred from/to the slave on the bus. */
        uint16_t transferred_length;
};

/**
 * \internal
 *
 * \brief TWI master Interrupt Vectors
 *
 * The TWI master interrupt request entry points are conditionally compiled
 * for the TWI interfaces supported by the XMEGA MCU variant. All of these
 * entry points call a common service function, twi_master_interrupt_handler(),
 * to handle bus events.
 */
static void twi_master_interrupt_handler(volatile avr32_twim_t *const twi,
                struct twi_master_instance *instance);

#ifdef AVR32_TWIM0
struct twi_master_instance twim0_instance;

ISR(twim_master_interrupt_handler_twim0, AVR32_TWIM0_GROUP, CONF_TWIM_IRQ_LEVEL)
{
        twi_master_interrupt_handler(&AVR32_TWIM0, &twim0_instance);
}
#endif

#ifdef AVR32_TWIM1
struct twi_master_instance twim1_instance;

ISR(twim_master_interrupt_handler_twim1, AVR32_TWIM1_GROUP, CONF_TWIM_IRQ_LEVEL)
{
        twi_master_interrupt_handler(&AVR32_TWIM1, &twim1_instance);
}
#endif

#ifdef AVR32_TWIM2
struct twi_master_instance twim2_instance;

ISR(twim_master_interrupt_handler_twim2, AVR32_TWIM2_GROUP, CONF_TWIM_IRQ_LEVEL)
{
        twi_master_interrupt_handler(&AVR32_TWIM2, &twim2_instance);
}
#endif

/**
 * \internal
 *
 * \brief TWI master peripheral to instance conversion routine
 *
 * This function converts a base pointer to a TWI peripheral module into its
 * corresponding instance struct, which contains information about the module's
 * state.
 *
 * \return Corresponding instance struct for the given TWI module, or NULL if
 *         an invalid pointer is supplied
 */
static struct twi_master_instance *twi_master_instance_from_module(
                volatile avr32_twim_t *const twi)
{
        if (twi == NULL) {
                Assert(0);
        }
#ifdef AVR32_TWIM0
        else if ((uintptr_t)twi == (uintptr_t)&AVR32_TWIM0) {
                return &twim0_instance;
        }
#endif
#ifdef AVR32_TWIM1
        else if ((uintptr_t)twi == (uintptr_t)&AVR32_TWIM1) {
                return &twim1_instance;
        }
#endif
#ifdef AVR32_TWIM2
        else if ((uintptr_t)twi == (uintptr_t)&AVR32_TWIM2) {
                return &twim2_instance;
        }
#endif
        else {
                Assert(0);
        }

        return NULL;
}

static inline void twi_master_register_int_handlers(void)
{
#ifdef AVR32_TWIM0
        irq_register_handler(twim_master_interrupt_handler_twim0,
                        AVR32_TWIM0_IRQ, CONF_TWIM_IRQ_LEVEL);
#endif
#ifdef AVR32_TWIM1
        irq_register_handler(twim_master_interrupt_handler_twim1,
                        AVR32_TWIM1_IRQ, CONF_TWIM_IRQ_LEVEL);
#endif
#ifdef AVR32_TWIM2
        irq_register_handler(twim_master_interrupt_handler_twim2,
                        AVR32_TWIM2_IRQ, CONF_TWIM_IRQ_LEVEL);
#endif
}

/**
 * \internal
 *
 * \brief TWI master common interrupt handler.
 *
 *  This is the common master mode interrupt handler that manages TWI modules
 *  when their corresponding interrupt vector fires.
 *
 * \param twi       Base address of the TWI peripheral (i.e. &TWIC).
 * \param instance  Pointer to the TWI instance struct corresponding to the
 *                  given TWI peripheral.
 */
static void twi_master_interrupt_handler(volatile avr32_twim_t *const twi,
                struct twi_master_instance *instance)
{
        uint32_t status = twi->sr;
        const twi_package_t *current_package = instance->current_transfer;

        if (status & (AVR32_TWIM_SR_ANAK_MASK | AVR32_TWIM_SR_DNAK_MASK | AVR32_TWIM_SR_ARBLST_MASK)) {
                instance->status = (status & AVR32_TWIM_IER_ARBLST_MASK) ? ERR_BUSY : ERR_IO_ERROR;
                twi->CMDR.valid = false;
                twi->scr = -1;
                twi->idr = -1;
        }
        else if (status & AVR32_TWIM_SR_RXRDY_MASK) {           
                uint8_t *data = current_package->buffer;
                data[instance->transferred_length++] = twi->rhr;
        }
        else if (status & AVR32_TWIM_SR_TXRDY_MASK) {
                if (instance->sent_address_bytes < current_package->rw_address_length) {
                        uint8_t *data = (uint8_t *)&current_package->rw_address;
                        twi->thr = data[instance->sent_address_bytes++];
                }
                else if (instance->transferred_length < current_package->length) {
                        uint8_t *data = current_package->buffer;
                        twi->thr = data[instance->transferred_length++];                       
                }
        }
        else if (status & AVR32_TWIM_SR_IDLE_MASK) {
                if (instance->transferred_length == current_package->length) {
                        instance->status = STATUS_OK;
                }       
        }
       
        /* Fire user callback if one has been registered and the transfer is
         * no longer in progress. */
        if ((instance->status != OPERATION_IN_PROGRESS) && instance->callback)
                instance->callback(twi);       
}

static inline status_code_t twi_master_set_baud(volatile avr32_twim_t *const twi,
                const uint32_t baud)
{
        uint32_t f_prescaled;
        uint8_t cwgr_exp = 0;
       
        f_prescaled = (sysclk_get_pba_hz() / baud / 2);

        // f_prescaled must fit in 8 bits, cwgr_exp must fit in 3 bits
        while ((f_prescaled > 0xFF) && (cwgr_exp <= 0x7)) {
                // increase clock divider
                cwgr_exp++;

                // divide f_prescaled value
                f_prescaled /= 2;
        }
       
        if (cwgr_exp > 0x7) {
                return ERR_INVALID_ARG;
        }

        // set clock waveform generator register
        twi->cwgr = ((f_prescaled/2) << AVR32_TWIM_CWGR_LOW_OFFSET)
                        | ((f_prescaled - f_prescaled/2) << AVR32_TWIM_CWGR_HIGH_OFFSET)
                        | (   cwgr_exp << AVR32_TWIM_CWGR_EXP_OFFSET)
                        | (          0 << AVR32_TWIM_CWGR_DATA_OFFSET)
                        | (f_prescaled << AVR32_TWIM_CWGR_STASTO_OFFSET);
       
        return STATUS_OK;
}

/**
 * \brief Initializes the TWI master module.
 *
 *  Initializes the given TWI peripheral, ready for use in master mode.
 *
 * \param twi       Base address of the TWI peripheral (i.e. &AVR32_TWIM0).
 * \param baud      Baud rate of the TWI bus, in Hz.
 * \param callback  Function to call when the bus status changes.
 *
 * \return Current status of the corresponding TWI module, a value from
 *         \ref status_code_t.
 */
status_code_t twi_master_init(volatile avr32_twim_t *const twi,
                const uint32_t baud, const twi_master_callback_t callback)
{
        struct twi_master_instance *instance = twi_master_instance_from_module(twi);

        if (!baud) {
                return ERR_INVALID_ARG;
        }
       
        irqflags_t flags = cpu_irq_save();

        twi->idr = -1;
        twi->cr  = AVR32_TWIM_CR_MEN_MASK;
        twi->cr  = AVR32_TWIM_CR_SWRST_MASK;
        twi->scr = -1;
       
        if (twi_master_set_baud(twi, baud) != STATUS_OK) {
                return ERR_INVALID_ARG;
        }
       
        twi_master_register_int_handlers();
       
        instance->status = STATUS_OK;
        instance->callback = callback;

        cpu_irq_restore(flags);

        return STATUS_OK;
}

/**
 * \brief Retrieves the current status of the TWI master module.
 *
 * \param twi       Base address of the TWI peripheral (i.e. &AVR32_TWIM0).
 *
 * \return Current status of the corresponding TWI module, a value from
 *         \ref status_code_t.
 */
status_code_t twi_master_get_status(volatile avr32_twim_t *const twi)
{
        status_code_t status;
       
        irqflags_t flags = cpu_irq_save();

        status = twi_master_instance_from_module(twi)->status;

        cpu_irq_restore(flags);
       
        return status; 
}

/**
 * \brief Begins a transfer on the given master TWI bus.
 *
 *  Starts an asynchronous transfer on the given TWI master bus, with the given
 *  package.
 *
 * \param twi       Base address of the TWI peripheral (i.e. &AVR32_TWIM0).
 * \param package   Pointer to a TWI package to transfer.
 * \param read      Transfer direction, true to read, or false write.
 *
 * \return Current status of the corresponding TWI module, a value from
 *         \ref status_code_t.
 */
status_code_t twi_master_transfer(volatile avr32_twim_t *const twi,
        const twi_package_t *package, const bool read)
{
        status_code_t status;
       
        /* Do a sanity check on the arguments. */
        if ((twi == NULL) || (package == NULL)) {
                return ERR_INVALID_ARG;
        }

        struct twi_master_instance *instance = twi_master_instance_from_module(twi);
       
        irqflags_t flags = cpu_irq_save();
       
        /* Only start a new transfer if the bus is idle */
        if (instance->status != OPERATION_IN_PROGRESS) {
                instance->status = OPERATION_IN_PROGRESS;
                instance->current_transfer = package;
                instance->sent_address_bytes = 0;
                instance->transferred_length = 0;
                instance->read = read;
               
                twi->cr = AVR32_TWIM_CR_MEN_MASK;
                twi->cr = AVR32_TWIM_CR_SWRST_MASK;
                twi->cr = AVR32_TWIM_CR_MDIS_MASK;

                if (read) {
                        twi->cmdr = (package->chip_address << AVR32_TWIM_CMDR_SADR_OFFSET)
                                | (package->length << AVR32_TWIM_CMDR_NBYTES_OFFSET)
                                | (AVR32_TWIM_CMDR_VALID_MASK)
                                | (AVR32_TWIM_CMDR_START_MASK)
                                | (AVR32_TWIM_CMDR_STOP_MASK)
                                | (AVR32_TWIM_CMDR_READ_MASK);

                        if (package->rw_address_length) {
                                twi->ncmdr = twi->cmdr;
                                twi->cmdr = (package->chip_address << AVR32_TWIM_CMDR_SADR_OFFSET)
                                        | (package->rw_address_length << AVR32_TWIM_CMDR_NBYTES_OFFSET)
                                        | (AVR32_TWIM_CMDR_VALID_MASK)
                                        | (AVR32_TWIM_CMDR_START_MASK);
                        }
                }
                else {
                        twi->cmdr = (package->chip_address << AVR32_TWIM_CMDR_SADR_OFFSET)
                                | ((package->rw_address_length + package->length) << AVR32_TWIM_CMDR_NBYTES_OFFSET)
                                | (AVR32_TWIM_CMDR_VALID_MASK)
                                | (AVR32_TWIM_CMDR_START_MASK)
                                | (AVR32_TWIM_CMDR_STOP_MASK);
                }
               
                twi->ier = AVR32_TWIM_IER_ANAK_MASK | AVR32_TWIM_IER_DNAK_MASK |
                        AVR32_TWIM_IER_RXRDY_MASK | AVR32_TWIM_IER_TXRDY_MASK | AVR32_TWIM_IER_IDLE_MASK;
                twi->cr = AVR32_TWIM_CR_MEN_MASK;
        }
       
        /* Save status before unlocking global interrupts to preserve atomicity */
        status = instance->status;
        cpu_irq_restore(flags);

        return status;
}

/**
 * \brief Registers a callback for a given TWI module.
 *
 * \param twi       Base address of the TWI peripheral (i.e. &AVR32_TWIM0).
 * \param callback  Function to call when the bus status changes.
 */
void twi_master_set_callback(volatile avr32_twim_t *const twi,
                const twi_master_callback_t callback)
{
        twi_master_instance_from_module(twi)->callback = callback;
}


- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Jun 15, 2012 - 08:23 AM
Moderator


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway

Oh, and the header:

Code:
#ifndef _TWIM_H_
#define _TWIM_H_

/**
 * \defgroup group_xmega_drivers_twi_twim TWI Master
 *
 * \ingroup group_xmega_drivers_twi
 *
 *  @{
 */

#ifdef __cplusplus
extern "C" {
#endif

#include <avr32/io.h>
#include <compiler.h>
#include <status_codes.h>
#include <sysclk.h>

#include "conf_twim.h"

/** \brief TWI master bus package struct
 *
 *  Package descriptor for a TWI master packet to transfer on the bus.
 */
typedef struct {
        /*! Address of the slave to communicate with on the bus. */
        uint8_t chip_address;
       
        /*! Logical address within the slave. */
        uint32_t rw_address;
       
        /*! Length of the logical address within the slave to send. */
        uint8_t rw_address_length;

        /*! Pointer to a buffer where the data to transfer is located. */
        void *buffer;

        /*! Length of the data to transfer on the bus. */
        uint16_t length;
} twi_package_t;

/**
 * \brief Callback function type for a TWI master asynchronous callback.
 *
 * \param twi       Base address of the TWI peripheral (i.e. &TWIC).
 */
typedef void (*twi_master_callback_t)(volatile avr32_twim_t *const twi);

status_code_t twi_master_init(volatile avr32_twim_t *const twi, const uint32_t baud,
                const twi_master_callback_t callback);

status_code_t twi_master_get_status(volatile avr32_twim_t *const twi);

status_code_t twi_master_transfer(volatile avr32_twim_t *const twi,
        const twi_package_t *package, const bool read);

/**
 * \brief Begins a read transfer on the given master TWI bus.
 *
 *  Starts an asynchronous read transfer on the given TWI master bus, with the
 *  given package.
 *
 * \param twi       Base address of the TWI peripheral (i.e. &TWIC).
 * \param package   Pointer to a TWI package to transfer.
 *
 * \return Current status of the corresponding TWI module, a value from
 *         \ref status_code_t.
 */
static inline status_code_t twi_master_read(volatile avr32_twim_t *const twi,
        const twi_package_t *package)
{
        return twi_master_transfer(twi, package, true);
}

/**
 * \brief Begins a write transfer on the given master TWI bus.
 *
 *  Starts an asynchronous write transfer on the given TWI master bus, with the
 *  given package.
 *
 * \param twi       Base address of the TWI peripheral (i.e. &TWIC).
 * \param package   Pointer to a TWI package to transfer.
 *
 * \return Current status of the corresponding TWI module, a value from
 *         \ref status_code_t.
 */
static inline status_code_t twi_master_write(volatile avr32_twim_t *const twi,
        const twi_package_t *package)
{
        return twi_master_transfer(twi, package, false);
}

void twi_master_set_callback(volatile avr32_twim_t *const twi, twi_master_callback_t callback);

#ifdef __cplusplus
}
#endif

/** @} */

#endif /* _TWIM_H_ */


- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
sma
PostPosted: Jun 20, 2012 - 07:37 AM
Posting Freak


Joined: Jan 14, 2007
Posts: 1836
Location: Nantes, France

Hi Dean

Can (did?) you attach the patch to the ASF bugzilla?

thanks Smile
-sma
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jun 20, 2012 - 08:05 AM
Moderator


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway

The full code is in branch bug1932 - Christian is reviewing it and Xavier will merge it once it's been signed off on.

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Jun 21, 2012 - 08:17 AM
Moderator


Joined: Jan 23, 2004
Posts: 9826
Location: Trondheim, Norway

Oh whoops, I thought this was the DFLL bug thread. This is actually in bug1915, where I was attempting to revamp all the TWI drivers, but only got through the XMEGA TWIM/TWIS and UC3 TWIM before I heard that Nantes was working on their own version and abandoned my own.

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Theguigz
PostPosted: Jun 22, 2012 - 10:56 PM
Newbie


Joined: Mar 17, 2011
Posts: 14
Location: Montreal

Thanks Dean for the example !

Based on that I have posted a project on AVR Freakfor TWIM for UC3C in C++ fully interrupt based that support multiple TWI device for the same chip :

http://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_type=project&item_id=3558

_________________
Guillaume Charland
 
 View user's profile Send private message Send e-mail Visit poster's website 
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