|
|
View previous topic :: View next topic |
Author |
Message |
twidget
Joined: 21 Feb 2013 Posts: 32 Location: Orange County, California
|
Webserver Controlled DSP ADAU1701 |
Posted: Thu Mar 13, 2014 1:09 am |
|
|
Hello everyone. I have been away from CCS for awhile but decided to use the compiler on my next project. Im rusty so I am sure I'll need some help. I though maybe I would began by explaining my project and where I'm at. Currently I have been developing with the mbed but will port over to PIC32.
The Project:
Using AnalogDevices ADAU1701 DSP Chip and a PIC32, I am creating a webserver controlled class D amp. The electronics for the amp are worked out so this project is devoted to the DSP/Webserver control side.
Background:
The ADAU1701 is a feature rich DSP. Using SigmaStudio software the user is able to drag-&-drop everything from filters to volume controls. The ADAU1701 is able to operate in self-boot mode, (by pulling hex from an EEPROM @ boot up), or in I2C/SPI control mode, acting as a slave to a ucontroller. It helps to think of the ADAU1701 as an FPGA, thats because when a user configures their design, register addresses change. To simplify design the SigmaStudio software creates a few .h files (Based on the DSP design). If care is taken when naming the variables, a somewhat portable code can be generated.
SigmaStudio also provides a file named SigmaStudioFW.h This is where the user writes 'macros' to implement ucontroller coms. Their is an example for one of the "macro/functions" and I tried to emulat it and port it over to the mbed platform, however I am missing something. (My C is not as strong as it needs to be)
For testing I designed a simple DSP project.
Its nothing more then a sine-wave generator, mute switch, and output DAC.
after compiling the project I saved the generated files and included them in a project on the mbed compiler.
Next I went to work trying to port over the example code I found for SigmaStudioFW.h The default SigmaStudioFW.h file is located in the installed directory of SigmaStudio software, but I found an example written for an ARM Cortex M3.
SigmaStudioFW.h is just a skeleton and its intentions is to allow the user to write code for which ever functions they need. The first function to start with is the
Code: | void SIGMA_WRITE_REGISTER_BLOCK(int devAddress, int address, int length, ADI_REG_TYPE *pData); |
This function is important because another function; default_download(); uses the block initialize the ADAU1701 in place of an EEPROM. (sends the HEX to the DSP to config the device)
Below is AnalogDevices method of dealing with the function.
Code: | /*
* File: SigmaStudioFW.h
*
* Description: SigmaStudio System Framwork macro definitions. These
* macros should be implemented for your system's software.
*
* This software is distributed in the hope that it will be useful,
* but is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* This software may only be used to program products purchased from
* Analog Devices for incorporation by you into audio products that
* are intended for resale to audio product end users. This software
* may not be distributed whole or in any part to third parties.
*
* Copyright © 2008 Analog Devices, Inc. All rights reserved.
*/
#ifndef __SIGMASTUDIOFW_H__
#define __SIGMASTUDIOFW_H__
/*
* TODO: Update for your system's data type
*/
typedef unsigned short ADI_DATA_U16;
typedef unsigned char ADI_REG_TYPE;
extern vu16 Tx_Idx, Rx_Idx;
extern vu16 NextBufferEnd, ThisBufferSize;
extern u8 I2C1_Buffer_Tx[];
#define Address_Length 2
void SIGMA_WRITE_REGISTER_BLOCK(int devAddress, int address, int length, ADI_REG_TYPE *pData);
void SIGMA_WRITE_DELAY(int devAddress, int length, ADI_REG_TYPE *pData );
/*
* Parameter data format
*/
#define SIGMASTUDIOTYPE_FIXPOINT 0
#define SIGMASTUDIOTYPE_INTEGER 1
/*
* Write to a single Device register
*/
#define SIGMA_WRITE_REGISTER( devAddress, address, dataLength, data ) {/*TODO: implement macro or define as function*/}
/*
* TODO: CUSTOM MACRO IMPLEMENTATION
* Write to multiple Device registers
*/
void SIGMA_WRITE_REGISTER_BLOCK(int devAddress, int address, int length, ADI_REG_TYPE *pData )
{
int ii = 0;
int zz = 0;
Tx_Idx = 0;
/*----- Transmission Phase -----*/
ThisBufferSize = Address_Length + length;
I2C1_Buffer_Tx[0] = (address & 0xFF00)>>8;
I2C1_Buffer_Tx[1] = address & 0x00FF;
for(zz=0;zz<length;zz++)
{
I2C1_Buffer_Tx [zz + Address_Length] = pData[zz];
}
Tx_Idx = 0;
for(ii =0;ii < ThisBufferSize;ii++)
{
NextBufferEnd = ThisBufferSize;//I2C1_numbytes[ii];
if(ii == 0) I2C_GenerateSTART(I2C1, ENABLE);
/* Send data */
while(Tx_Idx < NextBufferEnd)
{
}
}
}
void SIGMA_WRITE_DELAY(int devAddress, int length, ADI_REG_TYPE *pData )
{
// int cnt=0;
int nCount=0;
//int data_length = length - Address_Length;
// ADI_REG_TYPE data[4]={0x05, 0xF5, 0xE1, 0x00};
// for(cnt=0; cnt<data_length; cnt++)
// {
// nCount &= pData[cnt] >> (8*cnt);
// }
// for(cnt=0; cnt<4; cnt++)
// {
// nCount += data[cnt];
// nCount = nCount<<(8);
//
// }
//nCount=0xFFFFFF;
//nCount=0x15752A00; //5 secs approx
//nCount=0x05F5E100; //5 secs approx
nCount=0xFFFFF;
for(; nCount != 0; nCount--);
}
/*
* Read device registers
*/
#define SIGMA_READ_REGISTER( devAddress, address, length, pData ) {/*TODO: implement macro or define as function*/}
/*
* Set a register field's value
*/
#define SIGMA_SET_REGSITER_FIELD( regVal, fieldVal, fieldMask, fieldShift ) \
{ (regVal) = (((regVal) & (~(fieldMask))) | (((fieldVal) << (fieldShift)) && (fieldMask))) }
/*
* Get the value of a register field
*/
#define SIGMA_GET_REGSITER_FIELD( regVal, fieldMask, fieldShift ) \
{ ((regVal) & (fieldMask)) >> (fieldShift) }
/*
* Convert a floating-point value to SigmaDSP (5.23) fixed point format
* This optional macro is intended for systems having special implementation
* requirements (for example: limited memory size or endianness)
*/
#define SIGMASTUDIOTYPE_FIXPOINT_CONVERT( _value ) {/*TODO: IMPLEMENT MACRO*/}
/*
* Convert integer data to system compatible format
* This optional macro is intended for systems having special implementation
* requirements (for example: limited memory size or endianness)
*/
#define SIGMASTUDIOTYPE_INTEGER_CONVERT( _value ) {/*TODO: IMPLEMENT MACRO*/}
#endif
|
I was able to modify the code and run it on the mbed however I am not convinced its working correctly. Aside from generating a start bit, I do not see where the function actually writes data over the I2C bus.
I can bit-bang the I2C stuff but thats ugly code and not fit for production, so I would like to lear the correct method.
I can post the mbed code I have but being a CCS forum... tomorrow I will look at the PIC32 Ethernet Dev board and write code for that. Any ideas in the mean time? |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
Re: Webserver Controlled DSP ADAU1701 |
Posted: Thu Mar 13, 2014 2:39 am |
|
|
If it was originally ARM code, the chances are high that the (previously buffered) data went out on interrupts. That was certainly the case with the ARMs I worked on. All that's needed to start a transfer is to write the start.
That's not easy to replicate on PICs, indeed as far as I'm aware with PICs each byte has to be sent programmatically rather than on interrupts. CCS C provides good support for I2C, both the hardware provided by many PICs and by software emulation, avoiding all the pain and effort of bit-banging by the programmer.
While bit-banging is certainly not elegant, if done well, it's certainly fit for production. Its what the software I2C emulation provided by CCS is, just that it's not visible at C source level, and hidden by default at assembler level, but it is there. Of course using the hardware is a much better way to go where such hardware is provided, which is most PICs, but from a C source point of view there's almost no difference.
Take a look at #USE_I2C and the associated I2C support stuff in CCS, but don't expect it to work the same as the ARM stuff. |
|
|
twidget
Joined: 21 Feb 2013 Posts: 32 Location: Orange County, California
|
|
Posted: Thu Mar 13, 2014 5:23 pm |
|
|
Thank-you RF_Developer;
I think your right about the interrupt driven I2C coms thing.
Code: |
if(ii == 0) I2C_GenerateSTART(I2C1, ENABLE);
/* Send data */
while(Tx_Idx < NextBufferEnd)
{
}
|
I2C_GenerateSTART(I2C1, ENABLE); must be how everything is started.
I was able to change that part to match the mbed style of I2C
Code: | if(ii == 0) i2c.write(devAddress, I2C1_Buffer_Tx, ThisBufferSize, true); |
and I do load the DSP with the config HEX, however I never exit the function, because I assume I need a while loop... how do I know when the buffer has sent? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Fri Mar 14, 2014 4:01 am |
|
|
Worth just saying, that on the DSPIC's, it is possible to do a similar form of I2C, with the DMA. You define a 'block' of data to send, and then setup the DMA to respond to the I2C interrupt, and send 'n' sequential characters. The reason the standard functions don't behave like the ARM ones, is that the more basic chips don't have this type of ability.
Using this approach, you get the INT_DMA for the selected controller, when the buffer has been sent.
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|