• AVR Freaks

Hot!ATSAMR34-XPRO, SERCOM I2C Master DMA Repeated Start

Author
Kevil
Starting Member
  • Total Posts : 45
  • Reward points : 0
  • Joined: 2019/09/09 13:29:33
  • Location: 0
  • Status: offline
2020/06/02 13:58:04 (permalink)
0

ATSAMR34-XPRO, SERCOM I2C Master DMA Repeated Start

By means of ASF Wizard I added DMAC - Direct Memory Access Controller (driver) and SERCOM I2C - Master Module I2C (driver) polled in Atmel Studio 7.0 and successfully compiled and run program trying to set slave GPS module (u-blox ZOE-M8Q) register to 0xFD and then read byte data at 0xFD and 0xFE. Unfortunately I do not know how to send Repeated Start after first write (0xFD), the SDA is then going to high (See under "MeasuRE") which is wrong. The GPS module doesn't recognize another 0x84 (0x42 GPS module address) and send NAK.
 
I would appreciate very much how to set SERCOM1 I2C Master DMA Write to set GPS REGISTER (pointer) to 0xFD and than immediately send Repeated Start to read 2 bytes (number of bytes waiting for read) at 0xFD, 0xFD (GPS internal REGISTER incremented automatically for each read). Sample example would help me.
 
#include <asf.h>

#define REGISTER_LENGTH 1
#define DATA_LENGTH 2
// UBX-NAV-POSLLH command for u-blox ZOE-M8Q GPS to get LAT, LON
static uint8_t buffer[DATA_LENGTH] = {
 0xFD,0x00,
};

#define SLAVE_ADDRESS 0x42
#define TIMEOUT 1000

// Globally accessible module structure:
struct i2c_master_module i2c_master_instance;

// Function for setting up the module:
static void configure_i2c_master(void)
{
 /* Initialize config structure and software module. */
 struct i2c_master_config config_i2c_master;
 i2c_master_get_config_defaults(&config_i2c_master);
 /* Change buffer timeout to something longer. */
 config_i2c_master.buffer_timeout = 10000;
 config_i2c_master.pinmux_pad0 = CONF_MASTER_SDA_PINMUX;
 config_i2c_master.pinmux_pad1 = CONF_MASTER_SCK_PINMUX;
 /* Initialize and enable device with config. */
 i2c_master_init(&i2c_master_instance, CONF_I2C_MASTER_MODULE, &config_i2c_master);
 i2c_master_enable(&i2c_master_instance);
}

// Globally accessible DMA module structure:
struct dma_resource register_resource;
struct dma_resource data_resource;
// Globally transfer done flag:
static volatile bool transfer_is_done = false;
// Globally accessible DMA transfer descriptor:
COMPILER_ALIGNED(16)
DmacDescriptor register_descriptor SECTION_DMAC_DESCRIPTOR;
COMPILER_ALIGNED(16)
DmacDescriptor data_descriptor SECTION_DMAC_DESCRIPTOR;

// Function for transfer done callback:
static void transfer_done(struct dma_resource* const resource )
{
 //UNUSED(resource);
 dma_start_transfer_job(&data_resource);
 i2c_master_dma_set_transfer(&i2c_master_instance, SLAVE_ADDRESS,
 DATA_LENGTH, I2C_TRANSFER_READ);
 
 while (!transfer_is_done) {
  /* Wait for transfer done */
 }
 transfer_is_done = true;
}

// Function for setting up the DMA resource:
static void configure_dma_resource(struct dma_resource *resource)
{
 struct dma_resource_config config;
 dma_get_config_defaults(&config);
 config.peripheral_trigger = CONF_I2C_DMA_TRIGGER;
 config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
 dma_allocate(resource, &config);
}

static void configure_dma_data_resource(struct dma_resource *resource)
{
 struct dma_resource_config config;
 dma_get_config_defaults(&config);
 config.peripheral_trigger = CONF_I2C_DMA_TRIGGER;
 config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
 dma_allocate(resource, &config);
}


// Function for setting up the DMA transfer descriptor:
static void setup_dma_descriptor(DmacDescriptor *descriptor)
{
 struct dma_descriptor_config descriptor_config;
 dma_descriptor_get_config_defaults(&descriptor_config);
 descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE;
 descriptor_config.dst_increment_enable = false;
 descriptor_config.block_transfer_count = REGISTER_LENGTH;
 descriptor_config.source_address = (uint32_t)buffer + REGISTER_LENGTH;
 descriptor_config.destination_address =
 (uint32_t)(&i2c_master_instance.hw->I2CM.DATA.reg);
 dma_descriptor_create(descriptor, &descriptor_config);
}

static void setup_dma_data_descriptor(DmacDescriptor *descriptor)
{
 struct dma_descriptor_config descriptor_config;
 dma_descriptor_get_config_defaults(&descriptor_config);
 descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE;
 descriptor_config.dst_increment_enable = false;
 descriptor_config.block_transfer_count = DATA_LENGTH;
 descriptor_config.source_address = (uint32_t)buffer + DATA_LENGTH;
 descriptor_config.destination_address =
 (uint32_t)(&i2c_master_instance.hw->I2CM.DATA.reg);
 dma_descriptor_create(descriptor, &descriptor_config);
}



int main (void)
{
 system_init();

 /* Insert application code here, after the board has been initialized. */
 
 configure_i2c_master();
 configure_dma_resource(&register_resource);
 configure_dma_data_resource(&data_resource);
 setup_dma_descriptor(&register_descriptor);
 setup_dma_data_descriptor(&data_descriptor);
 dma_add_descriptor(&register_resource, &register_descriptor);
 dma_add_descriptor(&data_resource, &data_descriptor);
 dma_register_callback(&register_resource, transfer_done,
 DMA_CALLBACK_TRANSFER_DONE);
 dma_enable_callback(&register_resource, DMA_CALLBACK_TRANSFER_DONE);
 
 dma_start_transfer_job(&register_resource);
 i2c_master_dma_set_transfer(&i2c_master_instance, SLAVE_ADDRESS,
 REGISTER_LENGTH, I2C_TRANSFER_WRITE);
 
 while (!transfer_is_done) {
  /* Wait for transfer done */
 }
}

Attached Image(s)

#1

0 Replies Related Threads

    Jump to:
    © 2020 APG vNext Commercial Version 4.5