Hi,
I have a custom board with 4xAFE4404 mapped to K65. My development environment is IAR and MQX4.2. The application is supposed to read data continuously from these sensors and push data achieving around 1Ksps from each channel. Individual AFE4404 read is equivalent to 48 bytes which comprises of slave address, register address, followed by device address and 3 bytes of data. This takes around 130us. My I2C clock is running at 400KHz. AFE4404 has a maximum clock of 400KHz and even K65 has maximum clock of 400KHz. Data rate is coming around 500-600sps as of now. To reduce the time consumed by I2C transaction the following changes were attempted.
I have attached the DMA section I was using and AFE4404 read code, please let me know if I am doing something wrong with configurations?
if((afe4404_data_ready_flag_4==true))
{
DMA_RX_Init(DMA_BASE_PTR, 18, 0,(uint32_t)(&(I2C1_D)),(uint32_t)&dma_data, 3, 1 ); //DMA SLAVE
I2C_C1_REG(I2C1_BASE_PTR) |= I2C_C1_DMAEN_MASK;
DMA_ERQ |= (DMA_ERQ_ERQ0_MASK | DMA_ERQ_ERQ1_MASK);
Reflectance_raw_IR_1 = afe4404_register_read_dma(AFE4404_PRPCT,afe4404_1,3);
.}
void DMA_RX_Init(DMA_MemMapPtr DMA_Channel, uint8_t dma_source, int index, uint32_t source_addr, uint32_t dest_addr, uint32_t num_bytes, uint32_t bytes_per_xfer){
/* num_bytes is total bytes */
/* setup depends on how many bytes per transfer */
uint32_t citer_biter = (num_bytes-1) / bytes_per_xfer;
uint32_t ssize_dsize_attr;
uint8_t ack_nak_array[3];
uint8_t data[3]; // to hold data
SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;
for(int i=0;i<3;i++)
data[i]=0x00;
DMAMUX_CHCFG_REG(DMAMUX_BASE_PTR,index) = 0x00;
/* setup ssize and dsize parameter for TCD ATTR register based on transfer size assigned above */
/* 0:8bit; 1:16-bit, 2:32-bit, 5:16-byte, 6:32-byte */
switch(bytes_per_xfer)
{
case 1: default:
ssize_dsize_attr = 0; break; /* 8-bit */
case 2:
ssize_dsize_attr = 1; break; /* 16-bit */
case 4:
ssize_dsize_attr = 2; break; /* 32-bit */
case 16:
ssize_dsize_attr = 5; break; /* 16-byte */
case 32:
ssize_dsize_attr = 6; break; /* 32-byte */
}
DMA_SADDR_REG(DMA_Channel, index) = (uint32_t)&I2C1_D;; // Source address
DMA_SOFF_REG(DMA_Channel, index) = 0x0000; // Source address increments 0 bytes (uint32)
DMA_SLAST_REG(DMA_Channel, index) = 0; // After the major loop ends the source address decrements the size of the buffer
DMA_DADDR_REG(DMA_Channel, index) = dest_addr; // Destination address
DMA_DOFF_REG(DMA_Channel, index) = bytes_per_xfer; // Destination offset increments
DMA_DLAST_SGA_REG(DMA_Channel, index) = -num_bytes; // Destination address shift, go to back to beginning of buffer
DMA_NBYTES_MLNO_REG(DMA_Channel, index) = bytes_per_xfer; // The minor loop moves by bytes per transfer
DMA_BITER_ELINKNO_REG(DMA_Channel, index) = citer_biter; // Major loop iterations
DMA_CITER_ELINKNO_REG(DMA_Channel, index) = citer_biter; // Set current interation count
DMA_ATTR_REG(DMA_Channel, index) = (DMA_ATTR_SSIZE(ssize_dsize_attr)|DMA_ATTR_DSIZE(ssize_dsize_attr)); // Source a destination size 0:8bit; 1:16-bit, 2:32-bit, 5:16-byte, 6:32-byte
DMA_CSR_REG(DMA_Channel, index) = DMA_CSR_INTMAJOR_MASK | DMA_CSR_DREQ_MASK; // Enable end of loop DMA interrupt, disable request at end of major iteration
for( int j=0; j <3 ; j++)
{
if(j >= (1))
{
ack_nak_array[j] = 0xA1 | I2C_C1_TXAK_MASK;
}
else
{
ack_nak_array[j] = 0xA1 & (~I2C_C1_TXAK_MASK);
}
}
DMA_SADDR_REG(DMA_Channel, 1 ) = (uint32_t)ack_nak_array; ; // Source address
DMA_SOFF_REG(DMA_Channel, 1) = 0x0000; // Source address increments 0 bytes (uint32)
DMA_SLAST_REG(DMA_Channel, 1) = 0; // After the major loop ends the source address decrements the size of the buffer
DMA_DADDR_REG(DMA_Channel, 1) = (uint32_t)&I2C_C1_REG(I2C1_BASE_PTR); // Destination address
DMA_DOFF_REG(DMA_Channel, 1) = bytes_per_xfer; // Destination offset increments
DMA_DLAST_SGA_REG(DMA_Channel, 1) = -num_bytes; // Destination address shift, go to back to beginning of buffer
DMA_NBYTES_MLNO_REG(DMA_Channel, 1) = bytes_per_xfer; // The minor loop moves by bytes per transfer
DMA_BITER_ELINKNO_REG(DMA_Channel, 1) = citer_biter; // Major loop iterations
DMA_CITER_ELINKNO_REG(DMA_Channel, 1) = citer_biter; // Set current interation count
DMA_ATTR_REG(DMA_Channel, 1) = (DMA_ATTR_SSIZE(ssize_dsize_attr)|DMA_ATTR_DSIZE(ssize_dsize_attr)); // Source a destination size 0:8bit; 1:16-bit, 2:32-bit, 5:16-byte, 6:32-byte
DMA_CSR_REG(DMA_Channel, 1) = DMA_CSR_INTMAJOR_MASK | DMA_CSR_DREQ_MASK; // Enable end of loop DMA interrupt, disable request at end of major iteration
DMAMUX_CHCFG_REG(DMAMUX_BASE_PTR,0) = (DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(dma_source)); // DMA source DMA Mux to tie source to DMA channel
}
void DMA_TX_Init(DMA_MemMapPtr DMA_Channel, uint8_t dma_source, int index, uint32_t source_addr, uint32_t dest_addr, uint32_t num_bytes, uint32_t bytes_per_xfer) {
/* num_bytes is total bytes */
/* setup depends on how many bytes per transfer */
uint32_t citer_biter = num_bytes / bytes_per_xfer;
uint32_t ssize_dsize_attr;
switch(bytes_per_xfer)
{
case 1: default:
ssize_dsize_attr = 0; break; /* 8-bit */
case 2:
ssize_dsize_attr = 1; break; /* 16-bit */
case 4:
ssize_dsize_attr = 2; break; /* 32-bit */
case 16:
ssize_dsize_attr = 5; break; /* 16-byte */
case 32:
ssize_dsize_attr = 6; break; /* 32-byte */
}
DMAMUX_CHCFG_REG(DMAMUX_BASE_PTR,index) = (DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(dma_source)); // DMA source DMA Mux
DMA_SADDR_REG(DMA_Channel, index) = source_addr; // Source address
DMA_SOFF_REG(DMA_Channel, index) = bytes_per_xfer; // Source address increments by number of bytes per transfer
DMA_SLAST_REG(DMA_Channel, index) = -num_bytes; // After the major loop ends, reset pointer to beginning of buffer
DMA_DADDR_REG(DMA_Channel, index) = dest_addr ; // Destination address
DMA_DOFF_REG(DMA_Channel, index) = 0x0; // Destination offset increments 0 bytes (uint32)
DMA_DLAST_SGA_REG(DMA_Channel, index) = 0; // Destination address shift
DMA_NBYTES_MLNO_REG(DMA_Channel, index) = bytes_per_xfer; // The minor loop moves 32 bytes per transfer
DMA_BITER_ELINKNO_REG(DMA_Channel, index) = citer_biter; // Major loop iterations
DMA_CITER_ELINKNO_REG(DMA_Channel, index) = citer_biter; // Set current interation count
DMA_ATTR_REG(DMA_Channel, index) = (DMA_ATTR_SSIZE(ssize_dsize_attr) | DMA_ATTR_DSIZE(ssize_dsize_attr)); // Source a destination size 0:8bit; 1:16-bit, 2:32-bit, 5:16-byte, 6:32-byte
DMA_CSR_REG(DMA_Channel, index) = DMA_CSR_INTMAJOR_MASK | DMA_CSR_DREQ_MASK; // Enable end of loop DMA interrupt; clear ERQ @ end of major iteration
}
signed long afe4404_register_read_dma(unsigned char Reg_address,MQX_FILE_PTR fd,int n)
{
unsigned char configData[3]={0}; // Local variable to hold data read from AFE4404 registaer
unsigned char reg_address[2]; // Local variable to hold register address
signed long retVal=0; // Local variable to hold the 24 bit data read from registers
_mqx_int param,result; // Local variable to hold status of transaction
int count=0; // Local variable to hold number of bytes transferred via I2C
(void)count;
// Creating packet for transfer
reg_address[0]=Reg_address; // Copying register address from which value needs to be read
// Set I2C slave address
param = AFE4404_ADDRESS;
#ifndef DEBUG_PRINTF
printf (" Set I2C bus address to 0x%02x ... ", param);
#endif
if (I2C_OK != ioctl (fd, IO_IOCTL_I2C_SET_DESTINATION_ADDRESS, ¶m))
printf ("04_ERROR\n");
// Write register read command via I2C
count = fwrite(reg_address,1,1,fd);
// Wait for completion
result = fflush (fd);
// Restart I2C transfer for reading
if (I2C_OK != ioctl (fd, IO_IOCTL_I2C_REPEATED_START, NULL))
printf ("04_ERROR\n");
// Set read request for n number of bytes
param = n;
if (I2C_OK != ioctl (fd, IO_IOCTL_I2C_SET_RX_REQUEST, ¶m))
printf ("04_ERROR\n");
// Read all data
// result = fread (configData, 1, 3, fd);
//// if (result != n)
//// printf ("04_ERROR\n");
DMA_CSR_REG(DMA_BASE_PTR, 0) |= DMA_CSR_START_MASK; // Enable end of loop DMA interrupt, disable request at end of major iteration
I2C_C1_REG(I2C1_BASE_PTR) |= I2C_C1_DMAEN_MASK;
for(int temp=0; temp<5050; temp++);
I2C_C1_REG(I2C1_BASE_PTR) &= ~(I2C_C1_DMAEN_MASK | I2C_C1_TX_MASK);
// Stop I2C transfer
if (I2C_OK != ioctl (fd, IO_IOCTL_I2C_STOP, NULL))
printf ("04_ERROR\n");
// if(configData[0]!=0xFF)
// {
// // Creating 24 bit return value
// retVal = configData[0];
// retVal = (retVal << 8) | configData[1];
// retVal = (retVal << 8) | configData[2];
// }
//
// else
// { // to avoid larger spikes
// configData[0]=0;
// retVal=configData[0];
// retVal = (retVal << 8) | configData[1];
// retVal = (retVal << 8) | configData[2];
// }
//
// if (Reg_address >= 0x2A && Reg_address <= 0x2F)
// {
// if (retVal & 0x00200000) // check if the ADC value is positive or negative
// {
// retVal &= 0x003FFFFF; // convert it to a 22 bit value
// return (retVal^0xFFC00000);
// }
// }
// return retVal;
}