Hi,
I'd like to interface an sensor board which uses the SPI BUS 12 bit 8-Channel TI TLV2548 to my MOD5270 Netburner. The TLV2548 command structure is a little more complicated than the LM70 temperature sensor SPI BUS GPRS example I found on the forum, so I was hoping someone has already written code QSPI code to read from this A/D.
For initial testing I can change the VCC of the TLV2548 to 3.3V to match the 3.3V input of the MOD5270, but long term I will need to use level translators from 5V to 3.3V to run the A/D on 5V to match the rest of the circuitry's voltage scaling. I'v seen that the MAX3390 can do this (Minimum quantity buy and not stocked by Digi-Key) or I could also use a LCX244 with the 5V input fault tolerance to connect the TLV2548 5V DO to the MOD5270 with ACT244 buffer to connect the MOD5270 outputs to the inputs of the TLV2548. I welcome any other elegant 3.3V to 5V translation ideas.
Thanks for any help!
Example A/D code using QSPI library for TI TLV2548 ?
-
- Posts: 4
- Joined: Wed Apr 22, 2009 9:07 pm
Example A/D code using QSPI library for TI TLV2548 ?
- Attachments
-
main.cpp
- GPRS example using QSPI communication to the LM70 temp sensor.
- (1.54 KiB) Downloaded 331 times
-
- tlv2548.pdf
- (1.03 MiB) Downloaded 384 times
- Chris Ruff
- Posts: 222
- Joined: Thu Apr 24, 2008 4:09 pm
- Location: topsail island, nc
- Contact:
Re: Example A/D code using QSPI library for TI TLV2548 ?
the following code is for the tlv1543 running out there on a MOD5270
If this help you:.. dude..you SO owe me..
Chris
/******************************************************************************
*
* Copyright 2009 Chris Ruff
* ALL RIGHTS RESERVED
*
*****************************************************************************/
#include "predef.h"
#include <stdio.h>
#include <ctype.h>
#include <includes.h>
#include <serial.h>
#include <string.h>
#include <iosys.h>
#include <constants.h>
#include <utils.h>
#include <ucos.h>
#include <stdarg.h>
#include <basictypes.h>
#include <stdlib.h>
#include <system.h>
#include <startnet.h>
#include <iosys.h>
#include <cfinter.h>
#include <math.h>
#include <serinternal.h>
#include <iointernal.h>
#define _ATOD_H_
#include "util.h"
#include "sim5270.h"
/*
The following steps are necessary to set up the QSPI 12-bit data transfers and a QSPI_CLK of
4.688 MHz. The QSPI RAM is set up for a queue of 16 transfers. All four QSPI_CS signals are
used in this example.
1. Write the QMR with 0xB308 to set up 12-bit data words with the data shifted on the falling
clock edge, and a QSPI_CLK frequency of 4.688 MHz (assuming a 75-MHz internal bus
clock).
2. Write QDLYR with the desired delays.
3. Write QIR with 0xD00F to enable write collision, abort bus errors, and clear any
interrupts.
4. Write QAR with 0x0020 to select the first command RAM entry.
5. Write QDR with 0x7E00, 0x7E00, 0x7E00, 0x7E00, 0x7D00, 0x7D00, 0x7D00, 0x7D00,
0x7B00, 0x7B00, 0x7B00, 0x7B00, 0x7700, 0x7700, 0x7700, and 0x7700 to set up four
transfers for each chip select. The chip selects are active low in this example.
6. Write QAR with 0x0000 to select the first transmit RAM entry.
7. Write QDR with sixteen 12-bit words of data.
8. Write QWR with 0x0F00 to set up a queue beginning at entry 0 and ending at entry 15.
9. Set QDLYR[SPE] to enable the transfers.
10.Wait until the transfers are complete. QIR[SPIF] is set when the transfers are complete.
11.Write QAR with 0x0010 to select the first receive RAM entry.
12. Read QDR to get the received data for each transfer.
13. Repeat steps 5 through 13 to do another transfer.
*/
#define QSPI_QDLYR_SPE (0x8000) // QDLYR: QSPI Delay Register
#define QSPI_BASE_QTR (0) // the Transmit RAM #0 memory location
#define QSPI_BASE_QRR (0x10) // the Transmit RAM #0 memory location
#define QSPI_BASE_QCR (0x20) // the Command RAM #0 memory location
volatile WORD buffer[16];
/******************************************************************
* QTR: QSPI Transmit Ram
* Write to Transmit ram register (register of TR) (data to transmit)
******************************************************************/
inline void QSPI_WRITE_QTR(int registerOfTR, int dataToTransmit)
{
sim.qspi.qar = (registerOfTR + QSPI_BASE_QTR);
sim.qspi.qdr = dataToTransmit;
};
/******************************************************************
* QRR: QSPI Recieve Ram
* Read from recieve ram register (register of RR) (data to recieve)
******************************************************************/
inline WORD QSPI_READ_QRR(int registerOfRR)
{
sim.qspi.qar = (registerOfRR + QSPI_BASE_QRR);
return sim.qspi.qdr;
};
/******************************************************************
* QCR: QSPI Command RAM
* Write to command register (register of CR), (control information data)
******************************************************************/
inline void QSPI_WRITE_QCR(int registerOfCR, int controlInformationData)
{
sim.qspi.qar=(registerOfCR + QSPI_BASE_QCR);
sim.qspi.qdr=controlInformationData;
};
void SetupATOD()
{
// to setup QSPI Pin Assignment Register for
// QSPI_CS1, QSPI_CS0, QSPI_CLK, QSPI_DIN, QSPI_DOUT
// See manual to setup CS3 or CS2
sim.gpio.par_qspi = 0xFF;
//MSRT, DOHIE, 10 bit, CPOL, CPHA BAUD
// 1 1 10 10 0 0 01110110
// 1110 1000 0111 0110
//
sim.qspi.qmr = 0xE888;
//sim.qspi.qmr = 0xE876;
//
//
//CSIV
//
// 0001 1111 0000 0000
//sim.qspi.qwr = 0x1F00;
//
// 0001 0001 0000 0000 only one transfer
sim.qspi.qwr = 0x1000;
//nil
sim.qspi.qir = 0x00;
}
void Tester()
{
// Setup command ram
//
//
QSPI_WRITE_QCR(0x0, 0x4000);
/*
QSPI_WRITE_QCR(0x1, 0x0);
QSPI_WRITE_QCR(0x2, 0x0);
QSPI_WRITE_QCR(0x3, 0x0);
QSPI_WRITE_QCR(0x4, 0x0);
QSPI_WRITE_QCR(0x5, 0x0);
QSPI_WRITE_QCR(0x6, 0x0);
QSPI_WRITE_QCR(0x7, 0x0);
QSPI_WRITE_QCR(0x8, 0x0);
QSPI_WRITE_QCR(0x9, 0x0);
QSPI_WRITE_QCR(0xa, 0x0);
QSPI_WRITE_QCR(0xb, 0x0);
QSPI_WRITE_QCR(0xc, 0x0);
QSPI_WRITE_QCR(0xd, 0x0);
QSPI_WRITE_QCR(0xe, 0x0);
QSPI_WRITE_QCR(0xf, 0x0);
*/
// Setup transmit ram (fill with data)
QSPI_WRITE_QTR(0x0, 5 << 6);
/*
QSPI_WRITE_QTR(0x1, 0xF0a5);
QSPI_WRITE_QTR(0x2, 0xF05a);
QSPI_WRITE_QTR(0x3, 0xF0a5);
QSPI_WRITE_QTR(0x4, 0xF05a);
QSPI_WRITE_QTR(0x5, 0xF0a5);
QSPI_WRITE_QTR(0x6, 0xF05a);
QSPI_WRITE_QTR(0x7, 0xF0a5);
QSPI_WRITE_QTR(0x8, 0xF05a);
QSPI_WRITE_QTR(0x9, 0xF0a5);
QSPI_WRITE_QTR(0xA, 0xF05a);
QSPI_WRITE_QTR(0xB, 0xF0a5);
QSPI_WRITE_QTR(0xC, 0xF05a);
QSPI_WRITE_QTR(0xD, 0xF0a5);
QSPI_WRITE_QTR(0xE, 0xF05a);
QSPI_WRITE_QTR(0xF, 0xF0a5);
*/
//Initiate transer by setting SPE
sim.qspi.qdlyr = 0x8000;
// Wait for transfer to complete by checking SPE
while (sim.qspi.qdlyr & QSPI_QDLYR_SPE); // Polling
buffer[0] = QSPI_READ_QRR(0x0);
/*
buffer[1] = QSPI_READ_QRR(0x1);
buffer[2] = QSPI_READ_QRR(0x2);
buffer[3] = QSPI_READ_QRR(0x3);
buffer[4] = QSPI_READ_QRR(0x4);
buffer[5] = QSPI_READ_QRR(0x5);
buffer[6] = QSPI_READ_QRR(0x6);
buffer[7] = QSPI_READ_QRR(0x7);
buffer[8] = QSPI_READ_QRR(0x8);
buffer[9] = QSPI_READ_QRR(0x9);
buffer[10] = QSPI_READ_QRR(0xA);
buffer[11] = QSPI_READ_QRR(0xB);
buffer[12] = QSPI_READ_QRR(0xC);
buffer[13] = QSPI_READ_QRR(0xD);
buffer[14] = QSPI_READ_QRR(0xE);
buffer[15] = QSPI_READ_QRR(0xF);
*/
// Print message
printf("\nTransfer complete..read:%d",buffer[0]);
// for(int i=0; i<16; i++)
// {
// printf("Read %d at address %d", buffer, i);
// }
}
WORD GetAD(char cwhich)
{
WORD wval=0;
//sim.gpio.podr_datal &= ~4;
QSPI_WRITE_QCR(0x0, 0x4000);
QSPI_WRITE_QTR(0x0, cwhich << 6);
sim.qspi.qdlyr = 0x8000;
while (sim.qspi.qdlyr & QSPI_QDLYR_SPE); // Polling
wval = QSPI_READ_QRR(0x0);
// the second time returns the data for cWhich
// sim.qspi.qdlyr = 0x8000;
// while (sim.qspi.qdlyr & QSPI_QDLYR_SPE); // Polling
// wval = QSPI_READ_QRR(0x0);
//sim.gpio.ppdsdr_datal |= 4;
return wval;
}
void InitATOD()
{
SetupATOD();
}
If this help you:.. dude..you SO owe me..
Chris
/******************************************************************************
*
* Copyright 2009 Chris Ruff
* ALL RIGHTS RESERVED
*
*****************************************************************************/
#include "predef.h"
#include <stdio.h>
#include <ctype.h>
#include <includes.h>
#include <serial.h>
#include <string.h>
#include <iosys.h>
#include <constants.h>
#include <utils.h>
#include <ucos.h>
#include <stdarg.h>
#include <basictypes.h>
#include <stdlib.h>
#include <system.h>
#include <startnet.h>
#include <iosys.h>
#include <cfinter.h>
#include <math.h>
#include <serinternal.h>
#include <iointernal.h>
#define _ATOD_H_
#include "util.h"
#include "sim5270.h"
/*
The following steps are necessary to set up the QSPI 12-bit data transfers and a QSPI_CLK of
4.688 MHz. The QSPI RAM is set up for a queue of 16 transfers. All four QSPI_CS signals are
used in this example.
1. Write the QMR with 0xB308 to set up 12-bit data words with the data shifted on the falling
clock edge, and a QSPI_CLK frequency of 4.688 MHz (assuming a 75-MHz internal bus
clock).
2. Write QDLYR with the desired delays.
3. Write QIR with 0xD00F to enable write collision, abort bus errors, and clear any
interrupts.
4. Write QAR with 0x0020 to select the first command RAM entry.
5. Write QDR with 0x7E00, 0x7E00, 0x7E00, 0x7E00, 0x7D00, 0x7D00, 0x7D00, 0x7D00,
0x7B00, 0x7B00, 0x7B00, 0x7B00, 0x7700, 0x7700, 0x7700, and 0x7700 to set up four
transfers for each chip select. The chip selects are active low in this example.
6. Write QAR with 0x0000 to select the first transmit RAM entry.
7. Write QDR with sixteen 12-bit words of data.
8. Write QWR with 0x0F00 to set up a queue beginning at entry 0 and ending at entry 15.
9. Set QDLYR[SPE] to enable the transfers.
10.Wait until the transfers are complete. QIR[SPIF] is set when the transfers are complete.
11.Write QAR with 0x0010 to select the first receive RAM entry.
12. Read QDR to get the received data for each transfer.
13. Repeat steps 5 through 13 to do another transfer.
*/
#define QSPI_QDLYR_SPE (0x8000) // QDLYR: QSPI Delay Register
#define QSPI_BASE_QTR (0) // the Transmit RAM #0 memory location
#define QSPI_BASE_QRR (0x10) // the Transmit RAM #0 memory location
#define QSPI_BASE_QCR (0x20) // the Command RAM #0 memory location
volatile WORD buffer[16];
/******************************************************************
* QTR: QSPI Transmit Ram
* Write to Transmit ram register (register of TR) (data to transmit)
******************************************************************/
inline void QSPI_WRITE_QTR(int registerOfTR, int dataToTransmit)
{
sim.qspi.qar = (registerOfTR + QSPI_BASE_QTR);
sim.qspi.qdr = dataToTransmit;
};
/******************************************************************
* QRR: QSPI Recieve Ram
* Read from recieve ram register (register of RR) (data to recieve)
******************************************************************/
inline WORD QSPI_READ_QRR(int registerOfRR)
{
sim.qspi.qar = (registerOfRR + QSPI_BASE_QRR);
return sim.qspi.qdr;
};
/******************************************************************
* QCR: QSPI Command RAM
* Write to command register (register of CR), (control information data)
******************************************************************/
inline void QSPI_WRITE_QCR(int registerOfCR, int controlInformationData)
{
sim.qspi.qar=(registerOfCR + QSPI_BASE_QCR);
sim.qspi.qdr=controlInformationData;
};
void SetupATOD()
{
// to setup QSPI Pin Assignment Register for
// QSPI_CS1, QSPI_CS0, QSPI_CLK, QSPI_DIN, QSPI_DOUT
// See manual to setup CS3 or CS2
sim.gpio.par_qspi = 0xFF;
//MSRT, DOHIE, 10 bit, CPOL, CPHA BAUD
// 1 1 10 10 0 0 01110110
// 1110 1000 0111 0110
//
sim.qspi.qmr = 0xE888;
//sim.qspi.qmr = 0xE876;
//
//
//CSIV
//
// 0001 1111 0000 0000
//sim.qspi.qwr = 0x1F00;
//
// 0001 0001 0000 0000 only one transfer
sim.qspi.qwr = 0x1000;
//nil
sim.qspi.qir = 0x00;
}
void Tester()
{
// Setup command ram
//
//
QSPI_WRITE_QCR(0x0, 0x4000);
/*
QSPI_WRITE_QCR(0x1, 0x0);
QSPI_WRITE_QCR(0x2, 0x0);
QSPI_WRITE_QCR(0x3, 0x0);
QSPI_WRITE_QCR(0x4, 0x0);
QSPI_WRITE_QCR(0x5, 0x0);
QSPI_WRITE_QCR(0x6, 0x0);
QSPI_WRITE_QCR(0x7, 0x0);
QSPI_WRITE_QCR(0x8, 0x0);
QSPI_WRITE_QCR(0x9, 0x0);
QSPI_WRITE_QCR(0xa, 0x0);
QSPI_WRITE_QCR(0xb, 0x0);
QSPI_WRITE_QCR(0xc, 0x0);
QSPI_WRITE_QCR(0xd, 0x0);
QSPI_WRITE_QCR(0xe, 0x0);
QSPI_WRITE_QCR(0xf, 0x0);
*/
// Setup transmit ram (fill with data)
QSPI_WRITE_QTR(0x0, 5 << 6);
/*
QSPI_WRITE_QTR(0x1, 0xF0a5);
QSPI_WRITE_QTR(0x2, 0xF05a);
QSPI_WRITE_QTR(0x3, 0xF0a5);
QSPI_WRITE_QTR(0x4, 0xF05a);
QSPI_WRITE_QTR(0x5, 0xF0a5);
QSPI_WRITE_QTR(0x6, 0xF05a);
QSPI_WRITE_QTR(0x7, 0xF0a5);
QSPI_WRITE_QTR(0x8, 0xF05a);
QSPI_WRITE_QTR(0x9, 0xF0a5);
QSPI_WRITE_QTR(0xA, 0xF05a);
QSPI_WRITE_QTR(0xB, 0xF0a5);
QSPI_WRITE_QTR(0xC, 0xF05a);
QSPI_WRITE_QTR(0xD, 0xF0a5);
QSPI_WRITE_QTR(0xE, 0xF05a);
QSPI_WRITE_QTR(0xF, 0xF0a5);
*/
//Initiate transer by setting SPE
sim.qspi.qdlyr = 0x8000;
// Wait for transfer to complete by checking SPE
while (sim.qspi.qdlyr & QSPI_QDLYR_SPE); // Polling
buffer[0] = QSPI_READ_QRR(0x0);
/*
buffer[1] = QSPI_READ_QRR(0x1);
buffer[2] = QSPI_READ_QRR(0x2);
buffer[3] = QSPI_READ_QRR(0x3);
buffer[4] = QSPI_READ_QRR(0x4);
buffer[5] = QSPI_READ_QRR(0x5);
buffer[6] = QSPI_READ_QRR(0x6);
buffer[7] = QSPI_READ_QRR(0x7);
buffer[8] = QSPI_READ_QRR(0x8);
buffer[9] = QSPI_READ_QRR(0x9);
buffer[10] = QSPI_READ_QRR(0xA);
buffer[11] = QSPI_READ_QRR(0xB);
buffer[12] = QSPI_READ_QRR(0xC);
buffer[13] = QSPI_READ_QRR(0xD);
buffer[14] = QSPI_READ_QRR(0xE);
buffer[15] = QSPI_READ_QRR(0xF);
*/
// Print message
printf("\nTransfer complete..read:%d",buffer[0]);
// for(int i=0; i<16; i++)
// {
// printf("Read %d at address %d", buffer, i);
// }
}
WORD GetAD(char cwhich)
{
WORD wval=0;
//sim.gpio.podr_datal &= ~4;
QSPI_WRITE_QCR(0x0, 0x4000);
QSPI_WRITE_QTR(0x0, cwhich << 6);
sim.qspi.qdlyr = 0x8000;
while (sim.qspi.qdlyr & QSPI_QDLYR_SPE); // Polling
wval = QSPI_READ_QRR(0x0);
// the second time returns the data for cWhich
// sim.qspi.qdlyr = 0x8000;
// while (sim.qspi.qdlyr & QSPI_QDLYR_SPE); // Polling
// wval = QSPI_READ_QRR(0x0);
//sim.gpio.ppdsdr_datal |= 4;
return wval;
}
void InitATOD()
{
SetupATOD();
}
Real Programmers don't comment their code. If it was hard to write, it should be hard to understand
- Chris Ruff
- Posts: 222
- Joined: Thu Apr 24, 2008 4:09 pm
- Location: topsail island, nc
- Contact:
Re: Example A/D code using QSPI library for TI TLV2548 ?
You don't need anything fancy to do the level translation for inputs just feed 3.3volt signals into 5 volt devices. The other direction use, like, a 330 ohm resistor and if you are feeling particularly anal slam a 1n4148 diode in there to keep the signal from going above the 3.3v power line.
By all means, check the data sheets carefully for thresholds and input protection diodes and max currents and the ilk, but don't place those dual voltage level shifters in there unless there is some pressing need-for-speed or something.
OH- and the code I sent out. It is out-of-phase by one reading (the Chip's fault) . Keep an array of AD output words and feed it in a loop (off by one) in the PIT interrupt to maintain the list of 10 AD values
Chris
By all means, check the data sheets carefully for thresholds and input protection diodes and max currents and the ilk, but don't place those dual voltage level shifters in there unless there is some pressing need-for-speed or something.
OH- and the code I sent out. It is out-of-phase by one reading (the Chip's fault) . Keep an array of AD output words and feed it in a loop (off by one) in the PIT interrupt to maintain the list of 10 AD values
Chris
Real Programmers don't comment their code. If it was hard to write, it should be hard to understand
Re: Example A/D code using QSPI library for TI TLV2548 ?
Hi,
You are in luck. I have done a full driver for this exact A/D converter. The driver does not use the standard QSPI driver that is found in the NNDK. The standard NNDK QSPI driver is very easy to use and great for talking to devices where performance is not an issue. For A/D converters I almost always write custom drivers for the QSPI.
This driver was written for a board that had 2 TLV2548 ICs for 16 channels of A/D. I set up the QSPI to be running continuously so at any time the most recent conversions are already stored in the 16 QSPI queues. This will allow you to get much higher sampling rate and use virtually no CPU time asides from moving the data when calling the driver functions.
This driver was written for the MOD5282 so you will need to port a few things for the MOD5270.
Obviously the sim file changes:
#include <sim5282.h>
The SPI CS module pins may be different:
J2[30].function(PINJ2_30_SPI_CS0);
J2[26].function(PINJ2_26_SPI_CS3);
Timing of the QSPI delays will need to change since the clock is faster:
sim.qspi.qdlyr = 0x0010; // 0000 0000 0000 1000 Delay 256 33MHz clocks
The baud configuration bits will need to be changed in the qmr initialization for the faster clock:
sim.qspi.qmr = 0x8020; // 1000 0000 0010 0000
Asides from that the the rest of the code should not need any modification to run in the same 2 chip configuration. The QSPI modules are identical in hardware and sim structure which makes for a clean port between processors.
-Larry
You are in luck. I have done a full driver for this exact A/D converter. The driver does not use the standard QSPI driver that is found in the NNDK. The standard NNDK QSPI driver is very easy to use and great for talking to devices where performance is not an issue. For A/D converters I almost always write custom drivers for the QSPI.
This driver was written for a board that had 2 TLV2548 ICs for 16 channels of A/D. I set up the QSPI to be running continuously so at any time the most recent conversions are already stored in the 16 QSPI queues. This will allow you to get much higher sampling rate and use virtually no CPU time asides from moving the data when calling the driver functions.
This driver was written for the MOD5282 so you will need to port a few things for the MOD5270.
Obviously the sim file changes:
#include <sim5282.h>
The SPI CS module pins may be different:
J2[30].function(PINJ2_30_SPI_CS0);
J2[26].function(PINJ2_26_SPI_CS3);
Timing of the QSPI delays will need to change since the clock is faster:
sim.qspi.qdlyr = 0x0010; // 0000 0000 0000 1000 Delay 256 33MHz clocks
The baud configuration bits will need to be changed in the qmr initialization for the faster clock:
sim.qspi.qmr = 0x8020; // 1000 0000 0010 0000
Asides from that the the rest of the code should not need any modification to run in the same 2 chip configuration. The QSPI modules are identical in hardware and sim structure which makes for a clean port between processors.
-Larry
- Attachments
-
- TI_A2D_TLV2548.zip
- QSPI driver for two TLV2548 A/D converters continuously sampling
- (2.02 KiB) Downloaded 373 times
-
- Posts: 4
- Joined: Wed Apr 22, 2009 9:07 pm
Re: Example A/D code using QSPI library for TI TLV2548 ?
Thanks for the quick replies to help me out.
I'll let you know how it turns out when I get to work on it again this weekend.
(My real job gets in the way of the fun stuff...)
Wish me good luck!
Apr 30th - Thank you again. Once I got my 330 ohm pull up to +3.3V on the output of 74LCX07 Hex buffer to translate the +5 V DO of the A/D to the QSPI_IN of the netburner, it worked perfectly. Since Larry's code was already written for a TLV2548, I decided to try that first. Though the code was written to select two chips using two separate chip selects, it still worked perfect without any BAUD or Delay adjustments with just one chip hooked up to CS0. Guess I have room for analog expansion if I choose to add another chip. Thanks! Now to write the code to convert the raw readings from my RF sensor to read RF power and R & X impedance.
I'll let you know how it turns out when I get to work on it again this weekend.
(My real job gets in the way of the fun stuff...)
Wish me good luck!
Apr 30th - Thank you again. Once I got my 330 ohm pull up to +3.3V on the output of 74LCX07 Hex buffer to translate the +5 V DO of the A/D to the QSPI_IN of the netburner, it worked perfectly. Since Larry's code was already written for a TLV2548, I decided to try that first. Though the code was written to select two chips using two separate chip selects, it still worked perfect without any BAUD or Delay adjustments with just one chip hooked up to CS0. Guess I have room for analog expansion if I choose to add another chip. Thanks! Now to write the code to convert the raw readings from my RF sensor to read RF power and R & X impedance.