Home > Exploring Ideas, Hardware testing > Digital To Analog with Tiva C Launchpad and Energía

Digital To Analog with Tiva C Launchpad and Energía

TIVA_C_and_energia2



There are nice Energía diagrams for this LaunchPad in the Web.

Nevertheless, to become familiar with the board functionality and pin layout (and because enjoy drawing) decided to make a diagram. Tiva C Launchpad Pinout Diagram :

Tiva_C_Launchpad_Pinout_001b

Since my first contact with Arduino always wanted to generate waveforms and see them in an oscilloscope. Almost three years ago made some projects with the MSP430 LaunchPad, can be seen at the SeuPay’s YouTube channel. Then also did some test with the Stellaris LaunchPad.

After more than a year with a couple of unboxed Tiva C LaunchPads, decided to try some waveforms generation with the inexpensive 32 bit, 80 MHz ARM platform. Using Energía, began some experiments with the Tiva C :

-Generating waves with the MCP4725, I2C 12-Bits DAC .

-Generating waves with the AD7801 Parallel 8-Bit DAC.

Direct Port Manipulation was used to reach higher data updates (samples/second).



 

Tiva C Launchpad and MCP4725

The first experiment generates wave shapes using an external DAC (Digital-To-Analog Converter).

The first choice was to use the MCP4725 from Adafruit’s (SparkFun also has a version with different address).

TIVA_C_MCP4725_wiring

The following sketch fills an array with the values of a sine wave and feeds the  DAC continuously with those values.

The “Fast Mode Write Command” of the MCP4725 is used.


/*MCP4725_Sin_01.ino   Arduining 17 APR 2015

-Energia Sketch to be used with Tiva C Launchpad and the Adafruit's MCP4725.
-I2C Fast Mode Write Command is used.
-120 samples are producing a 3.62Hz sine wave  => 434 samples/second.

Based in the code at:
http://electronics.stackexchange.com/questions/29457/how-to-make-arduino-do-high-speed-i2c
 
*/

#include <Wire.h>
#include <math.h>

//The MCP4725 from Adafruit:
//  I2C address is 0x62 ( by default A0 has a 10k pull-down resistor ).
//  I2C address is 0x63 if A0 is connected to VCC. 
#define MCP4725_ADDR 0x62           //I2c address..

int ch[ 360 ] , cl[ 360 ];          //Arrays to load the sine wave.

//------------------------------------------------------------------------
void setup() {

  Wire.begin();           // SCL(3) and SDA(3) by default in Tiva C.
  Wire.setModule(0);      // Changing to SCL(0)and SDA(0),(PB_2 and PB_3). 

  analogWrite(GREEN_LED,25);        //led 10% on.
  
// Create a sine table of 360 points:
  for ( int i = 0; i <= 360; i++ ) {
    int c = sin( i * 3.141592 / 180 ) * 2047 + 2048;
    ch[ i ] = int( c / 256 );      // the 4 most significant bits.
    cl[ i ] = c - ch[ i ] * 256;   // the 8 least significant bits.
  }
}

//------------------------------------------------------------------------
void loop() {
  for ( int i = 0; i < 360; i=i+3 ) {     //Only 120 points are used.
    Wire.beginTransmission(MCP4725_ADDR);
    //Fast Mode Write Command.
    Wire.write( ch[ i ] );        // the 4 most significant bits.
    Wire.write( cl[ i ] );        // the 8 least significant bits.
    Wire.endTransmission();
  }
}

This is the final result.

TivaC_MCP4725_01

The DSO Nano is very handy because fits anywhere close to my desktop computer and

has become an excellent and inexpensive monitor for debugging.

DSO Nano screen capture of a  simulated ECG wave (using the same hardware):

AD7801_ECGsmall_2


 

Working with C and Direct Registers (and Ports) Manipulation

Thanks to the page: http://users.ece.utexas.edu/~valvano/Volume1/E-Book/

Where the professor Valvano, from University of Texas at Austin, teach how to Develop Embedded Systems with the ARM M 4 Processor (Tiva C LaunchPad).

The chapters are mainly designed to work in C but, with some adjusts, the Energía environment does pretty good.

To enable Direct Register Manipulation we need to include in Energía the hardware register definitions.

Just write at the beginning of your code:

#include     <tm4c123gh6pm.h>

This file is located in: C:\energia-0101E0015\hardware\lm4f\cores\lm4f\inc

I just made a copy and put it in: C:\energia-0101E0015\hardware\lm4f\libraries\tm4c123gh6pm

Notice that the file was copied inside a folder created with the same name.

(Surely there is a path to be included in Enegía to do this in a more elegant way).

Now you can use the Valvano’s examples in the Energía IDE, just remember to split the code appearing inside the main() function in two parts:

  – The configuration code goes inside the setup() function of Energía.

  – And the code running continuously is located inside the loop() function of Energía.

Is also possible to include Assembly code in Energía, but it needs another post.


 

Wiring the AD7801 8-Bits Parallel Digital to Analog Converter

A parallel DAC with 8 Bits is chosen to make the data transfer very fast.

Found the AD7801  at Mouser, the problem: (No DIP Package).

OK, let’s do some SMT work. With the DAC ordered and a  20 contact SOIC-to-DIP adapter.

…some SMT manual soldering…Breadboard-adapter-AD7801_02

A wiring diagram to connect the AD7801 to the Tiva C LaunchPad:

Tiva_C_AD7801_wiring

The AD7801, once soldered and wired, is very easy to operate. Simply put a new data in the PORTB and toggle PORTA bit 2 to produce a low pulse in the WR signal.

Did a A Quick-Ref of the chip:

QuickRef-AD7801

Then I had to study  Valvano’s code to understand how to deal with the Direct Register (and Ports) Manipulation.

First began to do the I/O Ports setup using the Direct Register manipulation, this part is not necessary, you can use Arduino code in Energía to do it. But was a good opportunity to learn  some details of the the ARM  Cortex M 4.

Finally, the code used to generate the fast data transfer between Tiva C launchpad and the AD7801:


/*AD7801_FastDAC.ino  Arduining.com 18 APR 2015

Testing the Tiva C LaunchPad and the AD7801 (Parallel Input 8-Bit DAC).
Using the PORTB to write the 8-Bit data.
Using PORTA bit 2 for the write signal (WR).

Results:
6 kHz    POINTS=256   ==>  1,536 Mega-samples/sec.
96 kHz   POINTS=16    ==>  1,536 Mega-samples/sec.
Note: faster if offset is a char.( 1,9 Mega-samples/sec.)
-----------------------------------------------------------------------------*/

#include  <tm4c123gh6pm.h>    // TM4C123GE6PM Register Definitions.
#include  <math.h>            // To calculate the sine table.

// bits 7-0 of port B address (Data).
#define ldata     (*((volatile unsigned long *)0x400053FC))
// bit 2 of port A address (WR signal).
#define wrsignal  (*((volatile unsigned long *)0x40004010))

#define POINTS    256    // Wave points.(256 max. to keep offset as char type)
#define PEAKVAL   128    // Wave Amplitud (128 max, inside 8-Bits range)
#define OFFSET    128    // Center of the wave (128 for full 8-Bits span).

int sintable[POINTS];    // Array to load the sin table data.
int offset=0;           // index to point the data inside sintable[].

//------------------------------------------------------------------------------
void setup(){

  PortB_Init();
  PortA_Init();

  // Fill the sin table with POINTS samples:
  for ( int i = 0; i <= POINTS; i++ ) {
    sintable[i] = sin( i * 3.141592 * 2 / POINTS ) * (PEAKVAL-1) + OFFSET ;
  }

}

void loop(){
    //Write data to the AD7801

    ldata= sintable[offset];        // Load value in the port B.
    wrsignal= 0;                    // WR signal to low.
    wrsignal= 4;                    // WR signal to high
    offset++;
    if((POINTS-offset)<=0)offset=0; // Keep offset in range.

  //  delayMicroseconds(2);           // To experiment different frequencies.
}

/*------------------------------------------------------------------------------
Subroutine to initialize port B all pins output.
Port B is used to output the data.
------------------------------------------------------------------------------*/
void PortB_Init(void){
  volatile unsigned long delay;
  SYSCTL_RCGC2_R |= 0x02;          // 1) activate Port B clock
  delay = SYSCTL_RCGC2_R;          // allow time for clock to stabilize
                                   // 2) no need to unlock PB7-0
  GPIO_PORTB_AMSEL_R &= ~0xFF;     // 3) disable analog functionality on PB7-0
  GPIO_PORTB_PCTL_R = 0x00000000;  // 4) configure PB7-0 as GPIO
  GPIO_PORTB_DIR_R |= 0xFF;        // 5) set PB7-0 as outputs
  GPIO_PORTB_AFSEL_R &= ~0xFF;     // 6) disable alt funct on PB7-0
  GPIO_PORTB_DR8R_R |= 0xFF;       // enable 8 mA drive on PB7-0
  GPIO_PORTB_DEN_R |= 0xFF;        // 7) enable digital I/O on PB7-0
}  

/*------------------------------------------------------------------------------
Subroutine to initialize port A pin 2 as output.
PA2 is used to drive the WR signal of the DAC.
------------------------------------------------------------------------------*/
void PortA_Init(void){
  volatile unsigned long delay;
  SYSCTL_RCGC2_R |= 0x01;           // 1) activate clock for Port A
  delay = SYSCTL_RCGC2_R;           // allow time for clock to start
                                    // 2) no need to unlock PA2 
  GPIO_PORTA_PCTL_R &= ~0x00000F00; // 3) regular GPIO 
  GPIO_PORTA_AMSEL_R &= ~0x04;      // 4) disable analog function on PA2 
  GPIO_PORTA_DIR_R |= 0x04;         // 5) set direction to output 
  GPIO_PORTA_AFSEL_R &= ~0x04;      // 6) regular port function 
  GPIO_PORTA_DEN_R |= 0x04;         // 7) enable digital port PA2
}
//End of code.


The complete assembly:

AD7801_FastSin_r

Two screenshots, thanks to the DSO Nano’s image capture function:

 A 6  kHz sine wave using POINTS= 256

and  a 95 kHz sine wave with POINTS= 16 .

The transfer speed is 1.536.000 samples/second.

AD8701_Speed_Test_2


 

Next steps:

Now we have a Sine Wave Generator, but the microcontroller is busy with this simple task.

If we need to do additional tasks like:

  • Change the frequency and (or) the amplitude on the fly.
  • Show  those values in a display.
  • Receive commands or transmit parameters serially.

 We need to use interruptions…

Thanks for reading Arduining blog.


Advertisements
  1. Müslüm İncedal
    May 13, 2016 at 2:17 AM

    #define TCD_SH 0x01
    #define TCD_CLK1 0x02
    #define TCD_CLK2 0x04
    #define TCD_BT 0x08
    #define TCD_RS 0x10

    void tcd1201d_setup()
    {
    DDRB = 0x1F;
    }

    unsigned char tcd1201d_out[1047];

    int tcd1201d_dark;

    void tcd1201d_read()
    {
    PORTB = TCD_SH | TCD_CLK1;
    PORTB = TCD_CLK1;

    for (int i = 0; i tcd1201d_dark) v = tcd1201d_dark;
    v = (tcd1201d_dark – v) / 2;
    if (v > 255) v = 255;
    tcd1201d_out[i] = v;
    }
    }

    void setup()
    {
    analogReference(DEFAULT);
    tcd1201d_setup();
    Serial.begin(115200);
    }

    void loop()
    {
    tcd1201d_read();
    tcd1201d_read();
    for (int i = 0; i < 1047; ++i)
    {
    Serial.print(tcd1201d_out[i], HEX);
    }
    Serial.println();
    }

    I do not understand register port, the above code Is it possible to convert your tm4c123

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: