Jake Graham
Jake Graham

Reputation: 11

Efficiently Controlling a DAC with a micro controller

I have a DAC8562 by analog devices. Here is a data sheet:

http://www.analog.com/media/en/technical-documentation/data-sheets/DAC8562.pdf

It is a parallel 12-bit DAC. I have a function written in C which controls GPIO pins to latch an input value to the DAC. My problem is that my function is rather slow. Here is the code:

void setOut(uint16_t data) {

//Set DATA
if (data & 0x01) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN2);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN2);
}
if (data & 0x02) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN0);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN0);
}
if (data & 0x04) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN1);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN1);
}
if (data & 0x08) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN7);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN7);
}
if (data & 0x10) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN6);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6);
}
if (data & 0x20) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN4);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN4);
}
if (data & 0x40) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P5, GPIO_PIN6);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN6);
}
if (data & 0x80) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN6);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN6);
}
if (data & 0x100) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN7);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN7);
}
if (data & 0x200) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN3);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN3);
}
if (data & 0x400) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P5, GPIO_PIN1);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN1);
}
if (data & 0x800) {
    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN5);
} else {
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN5);
}

// Set CE Low
MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P4, GPIO_PIN4);

// Set CE High
MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN4);}

The problem is the layout of the board requires the specific port/pin assignments I am using. As of now I am checking each bit individually and matching the output of the pin that bit represents as high or low. Is there a more efficient way of doing this?

Additional Info: I am using and MSP432P401R for a micro controller. I am using TI's driver library to control GPIO.

Upvotes: 0

Views: 254

Answers (2)

Phong
Phong

Reputation: 6768

Better code smart ! Here you have:

Solution 1:

struct param_t
{
  uint8_t bitmask;
  uint??_t gpio_port;
  uint??_t gpio_pin;
}

const param_t param[XXXX] = 
{
  {0x01, GPIO_PORT_P4, GPIO_PIN2},
  {0x02, GPIO_PORT_P4, GPIO_PIN0},
  {...},
}

void setOut(uint16_t data)
{
  for(int i=0; i<XXXX; i++)
  {
    if(data & param[i].bitmask)
    {
      MAP_GPIO_setOutputHighOnPin(param[i].gpio_port, param[i].gpio_pin)
    }
    else
    {
      MAP_GPIO_setOutputLowOnPin(param[i].gpio_port, param[i].gpio_pin)
    }
  }
}

Solution 2:

const callback_t callback[2] =
{
  MAP_GPIO_setOutputHighOnPin,
  MAP_GPIO_setOutputLowOnPin
}

void setOut(uint16_t data)
{
  callback[(int)(data & 0x01 == 0)](GPIO_PORT_P4, GPIO_PIN2};
  callback[(int)(data & 0x02 == 0)](GPIO_PORT_P4, GPIO_PIN0};
  ...
}

Solution 3: (Not sure it is possible)

After that i suppose that MAP_GPIO_setOutputXxxxOnPin is slow. It read modify then write back the register. Instead of multiple call to that function on the same port you should read it once, modify all its pin locally in the memory and then write it back once.

Upvotes: 1

Alexey Esaulenko
Alexey Esaulenko

Reputation: 549

Ooo, there is a lot of room for optimization!

  1. Replace this ugly MAP_GPIO_setOutputXXX () with fast raw register write:

    include "msp432.h" // it is from TI DriverLib too
    ...
    if (data & 0x01)
        P4OUT |= (1<<2);
    else
        P4OUT &= ~(1<<2);
    // and so on ...
    
  2. Instead of bitwise operations, use Cortex's core feature bit banding:

    // Convert SRAM address
    #define BITBAND_SRAM_REF 0x20000000
    #define BITBAND_SRAM_BASE 0x22000000
    #define BITBAND_SRAM(a,b) HWREG32((BITBAND_SRAM_BASE + (&(a) - BITBAND_SRAM_REF)*32 + (b*4))) 
    
    // Convert PERI address
    #define BITBAND_PERI_REF 0x40000000
    #define BITBAND_PERI_BASE 0x42000000
    #define BITBAND_PERI(a,b) HWREG32((BITBAND_PERI_BASE + (&(a) - BITBAND_PERI_REF)*32 + (b*4)))
    
    ...
    if (data & 0x01)
        BITBAND_PERI (P4OUT, 2) = 1;
    else
        BITBAND_PERI (P4OUT, 2) = 0;
    ...
    
  3. Modify bitband method, to remove if() statements. This is possible, because for bit band wrote only least significant bit is matter.

    BITBAND_PERI (P4OUT, 2) = data >> 0;  // bit 0
    BITBAND_PERI (P4OUT, 0) = data >> 1;  // bit 1
    BITBAND_PERI (P6OUT, 1) = data >> 2;  // bit 2
    BITBAND_PERI (P2OUT, 7) = data >> 3;  // bit 3
    // etc
    

Upvotes: 0

Related Questions