PWM wave files using AN2250

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

PWM wave files using AN2250

4,829 Views
blewis
Contributor I
I am trying to use/understand the code from AN2250 on wave files and the PWM on the H12 family. The program takes a normal .wav file and creates a series of flash pages of data. The data in the wave file is converted to ascii char's for some reason and as far as I can see when the data is again retrieved from the flash pages it is stored directly into the duty cycle register of the PWM. The modulus counter is used to interrupt at a hardcoded value, and the next value in the array is retrieved.

But this doesn't make any sense to me; why would ascii data be stored into duty cycle register. Is this an aribitrary offset that combined with the modulus counter interrupt generates the correct freguency?. Can someone please explain the methodology behind the code and how it generates a wave sound?

Or can anyone suggest other code to do the same function? This app code is poorly explained in my opinion.

Thanks.
Labels (1)
0 Kudos
12 Replies

988 Views
elid
Contributor I
I was using codewarrior IDE 5.7.0 build 2211 to compile AN2250SW3 and got the following errors:

Link Error: L1822: Symbol _LOAD_FAR_8 in file .......pwmcontroller.c.o is undefined

Link Error: L1822: Symbol _SET_PAGE in file .......Start12.c.o is undefined

Link Error: Link failed.

Please help me, thank you.


Message Edited by elid on 2008-08-14 10:01 AM
0 Kudos

988 Views
CrasyCat
Specialist III
Hello
 
I assume you are using banked data or constants in your application.
 
If this is the case, make sure to add the file datapage,c to your CodeWarrior project.
You find this file in {Install}\lib\hc12c\src folder (where {Install} stands for your CodeWarrior root installation directory)
 
CrasyCat
0 Kudos

988 Views
blewis
Contributor I
Steve
Thank you very much, this now makes sense. Missing that basic concept really muddled things for me.

All the best

Robert
0 Kudos

988 Views
Steve
NXP Employee
NXP Employee
Great, that's good to know. I wanted to make sure there weren't any issues here because this technology will find it's way into another upcoming app note - watch this space! :smileywink:
0 Kudos

988 Views
blewis
Contributor I
Hi Steve, thank you for the explanation.

But the problem I have is not where the data is coming from it is the data itself. In the createArray program, the binary data is extracted and written to and ascii file. Therefore if the data were, 0x33, 0x1C, 0x29 the data stored in the 'to be flash' pages is: 0x3333, 0x3149, 0x3239. This is because all the nibbles high and low of the byte of the binary data is converted to an ascii equivalent and stored in 1 - 14 ascii files called output01.c --> output14.c. These are then built and loaded into the flash pages in the 9s12.

this code is from the arrayCreator.c source

unsigned char convertASCII(unsigned char asciiNibble)
{   
   if (asciiNibble <= 0x09)         /* If nibble is less than 9 (ie. a number) */
      return (asciiNibble + 0x30); /* Return the ASCII code for this number */
   else                        /* Nibble must be a letter */
      return (asciiNibble + 0x37); /* Return the ASCII code for this letter */
}

So you can see the ascii conversion for each nibble.

Then in the 9s12, the data is extracted one byte at a time from the flash pages created above and stored in the duty cycle register as per the

code in pwcontroller.c

      Pwm.pwmdty[3].byte = *(wavPtr + sampleCounter);     /* Load sample to PWM duty register */
      sampleCounter ++;                             /*Increment sampleCounter */

Therefore ascii data is being stored in the duty cycle register as far as I can see.

Regards

Robert Lewis
0 Kudos

988 Views
Steve
NXP Employee
NXP Employee
Ah ok, that clarifies the question and I think I see where the misunderstanding arises. You need to look in main() to see what the program does with the data.

In arraycreator.c we see each sound byte in the wav file is firstly split into two bytes:
unsigned char sampleCheck, upperNibble, lowerNibble;
...
***arraycreator.c Line 187;
upperNibble = ((dataArray[(x + (y-1)*16383)] & 0xF0)>>4); /* Split data into nibbles for ASCII conversion */
lowerNibble = (dataArray[(x + (y-1)*16383)] & 0x0F);

So for a wav sample of 0x33 we now have upperNibble = 0x03 & lowerNibble = 0x03;

then these are placed in the output file for use by CodeWarrior:

***arraycreator.c Line 191;
asciiBuffer[0] = 0x30; /* ASCII "0" */
asciiBuffer[1] = 'x';
asciiBuffer[2] = convertASCII(upperNibble); /*Writes ASCII for upperNibble to asciiBuffer*/
asciiBuffer[3] = convertASCII(lowerNibble); /*Same as above but lowerNibble */

as you correctly say this converts each of the nibbles into an ASCII character.
The key is that it converts each of the nibbles into one ascii character. After the operation we now have asciiBuffer = {0x30,'x',0x33,0x33} which can be read as string "0x33" which is the ascii representation of the original binary value.
Each binary value in the wav is converted into a string of 4 ascii characters which CodeWarrior converts back to a single byte in flash.
0 Kudos

988 Views
blewis
Contributor I
Thank you for the advice and taking time to answer this problem.

I understand the input file is converted to an ascii array; my guess is that there is some restriction with CW and flashing the data that requires this work arround.  But here is the problem I can't understand with the code. As seen below, wavPtr is the page offset into the whole (converted) file in flash based on 16k pages, sampleCounter is the index into the current page. So what appears to be happening is that the ascii byte pair (sampleCounter is an integer) is being stored in the duty cyle register. What I don't understand is that all the bytes in the file as far as I can see from the Arraycreator code, are ascii. So this brings me back to the question, how can this work? There is no conversion back to binary, or does adding the constant offset simply add a offset of noise to the signal? But even that seems odd because this is an integer of two ascii bytes, so I guess it wouldn't be a valid offset. Or maybe I am reading the code wrong.



void
_modulusISR( void )
{
   /*Interrupt occurs when modulus down counter reaches 0*/
   Regs.porte.byte = 0xff;
   if (sampleCounter<(arraySize))                  /* If not end of file */
   {  
       Pwm.pwmdty[3].byte = *(wavPtr + sampleCounter);     /* Load sample to PWM duty register */
       sampleCounter ++;                           /*Increment sampleCounter */
   }  
   else
   {
       Timer.mcctl.byte = 0x4C;    /*Stop modulus down-counter */
       sampleCounter = 2;          /*Reset sample counter (offset to avoid reading size of file data) */
       samplePlayFlag = 1;         /*Set flag to inform main sample has been played */
   }

0 Kudos

988 Views
blewis
Contributor I
Thank you but no, I understand the file format of the wave file. The problem is the extraction of the data from the flash page and storage into the PWM duty cycle register. As far as I can see the data in the flash file is ascii, and the data stored into the PWM register is ascii, but the data in the wave file was binary. So I don't see how this works; ie putting ascii data into the pwm register. The data was stored into converted wave file as ascii and then extracted without conversion back to binary.
0 Kudos

988 Views
Steve
NXP Employee
NXP Employee
Maybe it would help if we can walk through the code to see where your concern is. Let me explain how I see this...
 
Looking at the code we could say:
const unsigned char myaudio[]={    //Compilable equivalent to wav file contents
0x1B,0xDD,0x80,0x80,0x7F,0x80,0x81,0x7F,0x81,0x80,
etc.
wavptr = myaudio;
sampleCounter = 0;
 
then
 
Pwm.pwmdty[3].byte = *(wavPtr + sampleCounter);     /* Load sample to PWM duty register */
for first event is:
Pwm.pwmdty[3].byte = *(wavPtr);      // = myaudio[0]
 
which is
Pwm.pwmdty[3].byte = 0x1B;     //Duty cycle byte = 0x1B
 
and 0x1B is the first value (byte) in the wave file
 
the second event is
Pwm.pwmdty[3].byte = *(wavPtr+1);       // = myaudio[1]
which is
Pwm.pwmdty[3].byte = 0xDD;     //Duty cycle byte = 0xDD = second value (byte) in the wave file
 
and so on...
0 Kudos

988 Views
Steve
NXP Employee
NXP Employee
I can't remember the exact format of the files that are produced but it's something like:
const unsigned char myaudio[]={
0x1B,0xDD,0x80,0x80,0x7F,0x80,0x81,0x7F,0x81,0x80,
etc.

Is it this file format that is not clear for you?
0 Kudos

988 Views
Steve
NXP Employee
NXP Employee
Think of the PWM as a Digital to Analog Converter. Storing a value in the duty cycle register causes a related analog value to appear on the filter output. The PC program simply takes the individual samples in the wav file and stores them in a format that can be easily compiled for the S12. The timer sets the sample rate for the output signal. In this way the S12 recreates the analog signal from the digital samples.
In a general sense the S12 is doing the same job as a CD player (although it takes the samples from a CD and uses dedicated audio hardware).
0 Kudos

988 Views
bigmac
Specialist III
Hello,
 
My understanding of AN2250 is that the utility arrayfilecreator.exe takes a .wav file as input, and outputs one or more .C files.  These output (ASCII) files actually contain constant unsigned char array data (as hexadecimal values), coded in C.  When these files are incuded within the main C program for the target, they will be compiled and linked at the same time as the target program, and then programmed into flash as binary data.  This is the data that is eventually fed to the PWM.
 
Regards,
Mac
 
0 Kudos