• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

ADC (audio sampling) and PWM (audio playback)

Status
Not open for further replies.

Pommie

Well-Known Member
Most Helpful Member
MrNobody said:
Below is part of the ADC code i found in microchip's TCP/IP stack.. I am trying to understand the reason why the code is written that way..

Code:
    // AN0 should already be set up as an analog input
    ADCON0bits.GO = 1;

    // Wait until A/D conversion is done
    while(ADCON0bits.GO);

    // AD converter errata work around (ex: PIC18F87J10 A2)
    #if !defined(__18F452)
    PRODL = ADCON2;
    ADCON2bits.ADCS0 = 1;
    ADCON2bits.ADCS1 = 1;
    ADCON2 = PRODL;
    #endif

    // Convert 10-bit value into ASCII string
    itoa(*((WORD*)(&ADRESL)), AN0String);
First question i have is regarding the "#if !defined(__18F452)" macro. Why does the code assign ADCON2 to PRODL, and after that make changes to ADCON followed by assigning PRODL back to ADCON2..?
Won't that overwrite the changes made in the middle..?

Second question is, these lines are part of a function that was called everytime the ADC need to sample the signal. Why does the ADC needs to be reinitialized everytime before the sample is taken..? I mean, why not just do it like below..?
Code:
    // Wait until A/D conversion is done
    while(ADCON0bits.GO);

    // Convert 10-bit value into ASCII string
    itoa(*((WORD*)(&ADRESL)), AN0String);
Is there any benefit in reinitializing the ADC before taking the samples..? Even in 18F4620's datasheet on page 227, it ask to reconfigure A/D module everytime before taking the sample (Step 7 which ask to go back to Step 1 or Step 2).
I think the clue is in the word errata. This is obviously a hardware bug that effects some ADC modules. If the Pic your using doesn't mention an errata sheet in the ADC section then I wouldn't worry about it. As you say, initialise it once and then just set the GO bit.

Mike.
 

MrNobody

New Member
Below is the code to read ADC input from RA0/AN0..
In the register, i set Vref- to VSS and Vref+ to VDD..
I am using 10MHz crystal with 4x PLL..

However, the when I monitor both ADRESH and ADRESL register, the register value doesn't change even if I change the input voltage..

I am not sure what I did wrong..

Code:
#include <p18F4620.h>
#include <delays.h>
#include <usart.h>
#include <stdio.h>

#pragma config WDT = OFF
#pragma config MCLRE = ON
#pragma config LVP = OFF
#pragma config OSC = HSPLL
#define CLOCK_FREQ		(40000000ul)      // Hz

void ADCInit();
void openPORTC();
void UARTInit();

void main()
{
	openPORTC();
	ADCInit();
	UARTInit();


	printf("ADC Test");


	while(1)
	{  
		while(ADCON0bits.GO);

		//According to errata
		PRODL = ADCON2;
		ADCON2bits.ADCS0 = 1;
		ADCON2bits.ADCS1 = 1;
		ADCON2 = PRODL;

		printf("%c\r\n", ADRESH);
	}
}


void ADCInit()
{
	ADCON1 = 0b00001110;
	ADCON0 = 0b00000011;
	ADCON2 = 0b00101010;
	ADCON0bits.ADON = 1;
}


void UARTInit()
{
	SPBRG = 64;
	TXSTA = 0b00100010;
	RCSTA = 0b10010000;
	BAUDCON = 0b00000000;
	TRISC = 0b10000001;
}
 

bananasiong

New Member
Hi,
I don't use C, but if I understand the code correctly, GO bit isn't set to start the conversion.
ADCON0bits.GO = 1
GO bit will be cleared once the conversion is done, so it has to be set again for the next conversion.
 

Pommie

Well-Known Member
Most Helpful Member
I looked for the errata sheet but couldn't find it. Have you found it? I would be interested to see it.

You may also want to check the TX pin, I believe it needs to be input for the UART to work.

Mike.
 

Pommie

Well-Known Member
Most Helpful Member
I still didn't find an explanation of the work around.

I think you should treat the chip as a fully working chip. Whatever your problem is not anything to do with an errata on chips that do TCPIP.

Did you listen to Bananasiong.

Post your most recent code and we will try and help.

Mike.
 

MrNobody

New Member
Yeah.. I tried what Bananasiong said and it works...
here is my updated code for those that is also learning ADC..
What is does is that it will sample voltage at AN0 and then send it through UART.

Code:
#include <p18F4620.h>
#include <delays.h>
#include <usart.h>
#include <stdio.h>

#pragma config WDT = OFF
#pragma config MCLRE = ON
#pragma config LVP = OFF
//#pragma config OSC = HSPLL
#define CLOCK_FREQ		(40000000ul)      // Hz

void ADCInit();
void UARTInit();

void main()
{
	ADCInit();
	UARTInit();


	printf("Test ADC");

	while(1)
	{  
		ADCON0bits.GO = 1;
		while(ADCON0bits.GO);

		PRODL = ADCON2;
   		ADCON2bits.ADCS0 = 1;
    		ADCON2bits.ADCS1 = 1;
    		ADCON2 = PRODL;

		printf("%c", ADRESH);

	}
}


void ADCInit()
{
	ADCON1 = 0b00001110;
	ADCON0 = 0b00000011;
	ADCON2 = 0b00101010;
	ADCON0bits.ADON = 1;
}


void UARTInit()
{
	SPBRG = 64;
	TXSTA = 0b00100010;
	RCSTA = 0b10010000;
	BAUDCON = 0b00000000;
	TRISC = 0b10000001; 
}
Oh.. by the way, the code above is only tested in Proteus.. I will try to sample sine wave and then look at the values..
 
Last edited:

MrNobody

New Member
Oh.. by the way, in the code above i commented "//#pragma config OSC = HSPLL".
That means that if I use 10MHz crystal, then the PIC is only running at 10MHz and not 40MHz rite..? If I want it to run at 40MHz then i need to uncomment that line rite..?

After looking at the datasheet, i can only see that the PLL can only be set to 4 and no other value.. is that right..?
 

bananasiong

New Member
Hi,
Since the PIC takes 4 clock cycles to complete one instruction, if a 10 MHz crystal is used and PLL enabled, the clock is running at 40 MHz, but the instruction cycle is 10 MIPS.
You can't run the PIC at 40 MIPS.
If the PLL is enabled, the crystal used must be 10 MHz or below. If it's not enabled, the crystal can be used is up to 20 MHz.
 

Pommie

Well-Known Member
Most Helpful Member
I see your still doing the errata code. The fact you are running it on a simulator means there is no need for this. I doubt there is any need on the actual hardware as the errata is specific to TCP/IP.

As for the question about the PLL, just try it.

Mike.
P.S. I do think it is polite when someone identifies your problem to acknowledge them. I'm talking about Bananasiong.
 

MrNobody

New Member
Pommie said:
I see your still doing the errata code. The fact you are running it on a simulator means there is no need for this. I doubt there is any need on the actual hardware as the errata is specific to TCP/IP.

As for the question about the PLL, just try it.

Mike.
P.S. I do think it is polite when someone identifies your problem to acknowledge them. I'm talking about Bananasiong.
Yeah.. I am still using the errata code.. coz the after trying all this, my tinal goal is to be able to send the voice through ethernet by using the TCP/IP stack..

Yeah.. I will try the PLL..

Oh.. i forgot to thank Bananasiong..

Bananasiong:
Thanks alot for your help..
Ahh.. i know what i'll do.. I'll click on your "myminicity" and build one house for u.. hehee...


P.S. umm..i dun really understand that PS part..
 

bananasiong

New Member
MrNobody said:
Ahh.. i know what i'll do.. I'll click on your "myminicity" and build one house for u.. hehee...
Ahhaa.. :D
My friend created that for me, but I don't know why did he select that country.
 

Pommie

Well-Known Member
Most Helpful Member
MrNobody said:
\P.S. umm..i dun really understand that PS part..
I was just saying that it is nice to acknowledge someone that has identified your problem. I was referring to the post where he explained that you have to set the Go bit to start a conversion.

Mike.
 

Hero999

Banned
Why do you want to do PWM?

Are you using a class-D output stage or something?

If you're just using the usual class AB stage then why not use an R2R converter?
 

MrNobody

New Member
Hero999 said:
Why do you want to do PWM?

Are you using a class-D output stage or something?

If you're just using the usual class AB stage then why not use an R2R converter?
Sorry.. i dunno much about amplifier..
I also don't know what R2R converter is.. but after going to http://www.eng.utah.edu/~bowen/DAC_Proj/8-bit_r2rdac_current_sources.html i think i kinda know what it is..
Is it like, i use 8 pins as output connect to a series of resistors and finally to an op-amp. Some sort of DAC converter where the most current will be present where all the 8 pins is HIGH (0b11111111) and no current where none of the pins are HIGH (0b00000000).
Won't that requires 8 pins on the PIC..?

The only reason why i use PWM is because it is possible to use 1 pin to generate audio.. I don't need additional components except low pass filter and speaker..

Actually, I my only focus is just to get some sound out..
 

bananasiong

New Member
Since there's built in PWM module in the PIC, it is easier way. Besides the IO pins required, the programming part is also easier ;)
 

ldanielrosa

New Member
Hero999, that's about how it looks. I'll also be making one as a proof of concept some day, though I won't throw nearly as much horsepower at it.

For what it's worth I see it from the other end. I want full resolution, and at 10 bits going into an h-bridge it'll be 9 bits differential. I'll need a 128Tins (PWM can run at oscillator speed) (or some multiple thereof) to keep in step with the PWM hardware. At 10MIPS and a maximum sample frequency of 30kHz or so I'd use a timed interrupt every 512Tins to take a new sample in the ADC. That gives me four PWM periods for every analog sample, possibly buying me some slack with my filter.

As for the sample rate, 10MIPS/512Tins is 19531.25 samples per second. Nyquist's limit is a brick wall, the actual cutoff is a bit lower. You'll get about 7.9 Khz
 

Oznog

Active Member
Still saying this sounds way more difficult than it needs to be.
dsPIC33F will do 40MIPs, and its 16-bit instruction set and DSP core is way more efficient per instruction. So if you need power that is it.

An Si3000 codec is pretty much stock. That's like $2. It'll be a microphone preamp, software adjustable, and a headset amp (although it's a pretty weak one actually). Maxim-IC's "DirectDrive" is the BEST headphone driver, they have codecs which have it and they have basic analog amp chips with it.

DirectDrive is where they use a charge pump to make a -Vdd and it's got an output that swings close to the rails with a high current capability. Then you can hook up a speaker without having to use differential mode OR large coupling caps and you still get +/- Vdd swing off of even 3.3V, which is nice- no separate regulator.

BTW, I don't know if you noticed this or not, but the Nyquist limit doesn't eliminate signals over Fsamp/2. Those components, if present, produce noise in the ADC data. And a simple RC filter does not have a sharp enough cutoff for this, there are some 2-stage active filters people often use. In general a codec chip will not need this hardware because they use oversampling- the ADC samples at a very high rate and they use a digital decimation filter to kick it down to the 8khz voice sampling rate.

I gotta note that making the filter costs about as much as just using the codec...
 
Last edited:
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading

 
Top