|
|
View previous topic :: View next topic |
Author |
Message |
juanodiy
Joined: 07 Sep 2012 Posts: 17
|
Multiplexing PCM data from 2 channels A/D CHANNEL (SOLVED) |
Posted: Fri Sep 07, 2012 2:37 pm |
|
|
Good afternoon, I'm from Bogota Colombia and i need help, because i don't find information about my topic. I need to digitize 2(two) analog signals, and send them for the same channel. It means multiplex the signal, after that for can be listened, but the signals don't have to mix, the signals must be able to be heard after a conversion D/A.
I decide to do 2 programs, and use 2 pic's of course. The pic is 18f452. In the first pic, I take the sampling of the two signals using A/D conversion, and send it every so often. In the second pic, I take the data (8bits in the portc) of the conversion (PCM word), and send it through the ports, (portc and portd) every so often. The problem is that i think the samples are not sufficient. But I'm using a delay of less than (50 us), it means sampling the signals at 20000 Hz, but isn't true because the time between the instructions take a time that i don't know.
Please help me i don't know what to do, for the signals can be multiplexed at the same time, the codes are below, for any suggestion I'll be very grateful.
PIC1, sampling
Code: |
#include <18f452.h>
#device adc=8
#use delay(clock=32000000)
#fuses HS,NOWDT
#byte trisa=0x85
#byte porta=0x05
#byte trisc=0x87
#byte portc=0x07
#byte trisb=0x86
#byte portb=0x06
#BYTE TRISD=0X88
#BYTE PORTD=0X08
#include <lcd.c>
#define aumenta input(PIN_c0) /// se definen los botenes de control
#define disminuye input(PIN_c1)
#define configurar input(PIN_c2)
int32 x=0.0005,valor=0,freq,valor2=0; //15 x q las demas instrucciones demoran +o- 110 useg en el main
void main()
{
lcd_init();
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(RA0_RA1_RA3_ANALOG);
trisc=0x03;
lcd_putc("muestreo:");
lcd_gotoxy(1,2);
lcd_putc("32000 Hz");
while(true)
{
set_adc_channel(0);
valor=read_adc(ADC_START_AND_READ);
output_b(valor);
delay_us(x);
set_adc_channel(1);
valor2=read_adc(ADC_START_AND_READ);
output_b(valor2);
}
}
|
PIC 2, multiplexing
Code: |
#include <18f452.h>
#device adc=8
#use delay(clock=20000000)
#fuses HS,NOWDT
#byte trisa=0x85
#byte porta=0x05
#byte trisc=0x87
#byte portc=0x07
#byte trisb=0x86
#byte portb=0x06
#BYTE TRISD=0X88
#BYTE PORTD=0X08
int16 x=0.00005;
int8 valor;
void main()
{
set_tris_b(0b11111111);
set_tris_c(0b00000000);
set_tris_d(0b00000000);
while(true)
{
valor=input_b();
output_c(valor);
delay_us(x);
valor=input_B();
output_d(valor);
}
}
|
Last edited by juanodiy on Wed Sep 19, 2012 10:09 pm; edited 2 times in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Sep 07, 2012 4:11 pm |
|
|
Quote: | #include <18f452.h>
#device adc=8
#use delay(clock=32000000)
#fuses HS,NOWDT |
The 18F452 data sheet says the maximum frequency for HS mode is
25 MHz. Are you using an external oscillator package ? If so, you
should use EC_IO instead of HS.
Or is this really a Proteus project ? Proteus doesn't care about the
oscillator or the fuse settings. But we don't like Proteus on the CCS board.
Quote: |
#byte trisa=0x85
#byte porta=0x05
#byte trisc=0x87
#byte portc=0x07
#byte trisb=0x86
#byte portb=0x06
#BYTE TRISD=0X88
#BYTE PORTD=0X08
|
These register addresses are all completely wrong for the 18F452.
They will not work. Look in the 18F452 data sheet for the correct values.
Or use the getenv() function to get the correct register address. See the
CCS manual.
An int32 is an integer, not a floating point number. 'x' will be set to 0
by the code above.
Quote: | setup_adc(ADC_CLOCK_INTERNAL);
|
The internal ADC clock is only recommended for operation at PIC
oscillator frequencies below 1 MHz, or if the PIC is in Sleep mode.
Look in this table in the 18F452 data sheet to find the correct ADC clock
divisor for your PIC oscillator frequency:
TABLE 17-1: TAD vs. DEVICE OPERATING FREQUENCIES
Quote: | set_adc_channel(0);
valor=read_adc(ADC_START_AND_READ);
|
According to the 18F452 data sheet, you should have a delay of at least
13 usec after you change the channel, and before you read the ADC.
See this section of the 18F452 data sheet:
EXAMPLE 17-1: CALCULATING THE MINIMUM REQUIRED ACQUISITION TIME
Do it like this:
Code: |
set_adc_channel(0);
delay_us(13);
valor=read_adc(); |
|
|
|
juanodiy
Joined: 07 Sep 2012 Posts: 17
|
|
Posted: Fri Sep 07, 2012 5:58 pm |
|
|
Hi, thanks to PCM programmer, I have been checking the code, and I make some changes, here are the codes:
PIC1
Code: |
#include <18f452.h>
#device adc=8
#use delay(clock=20000000)
#fuses HS,NOWDT
#byte trisa=0x85
#byte porta=0x05
#byte trisc=0x87
#byte portc=0x07
#byte trisb=0x86
#byte portb=0x06
#BYTE TRISD=0X88
#BYTE PORTD=0X08
#include <lcd.c>
int32 x=40,valor=0,freq,valor2=0; //15 x q las demas instrucciones demoran +o- 110 useg en el main
void main()
{
lcd_init();
setup_adc(ADC_CLOCK_DIV_32);
setup_adc_ports(RA0_RA1_RA3_ANALOG);
trisc=0x03;
lcd_putc("muestreo:");
lcd_gotoxy(1,2);
lcd_putc("32000 Hz");
while(true)
{
set_adc_channel(0);
delay_us(13);
valor=read_adc(ADC_START_AND_READ);
output_b(valor);
delay_us(x);
set_adc_channel(1);
delay_us(13);
valor2=read_adc(ADC_START_AND_READ);
output_b(valor2);
delay_us(x);
}
}
|
PIC 2
Code: |
#include <18f452.h>
#device adc=8
#use delay(clock=20000000)
#fuses HS,NOWDT
#byte trisa=0x85
#byte porta=0x05
#byte trisc=0x87
#byte portc=0x07
#byte trisb=0x86
#byte portb=0x06
#BYTE TRISD=0X88
#BYTE PORTD=0X08
int16 x=30;
int8 valor,valor2;
void main()
{
set_tris_b(0xFF);
set_tris_c(0x00);
set_tris_d(0x00);
while(true)
{
valor=input_b();
output_c(valor);
delay_us(x);
valor2=input_B();
output_d(valor);
delay_us(x);
}
}
|
I have been checking the PIC 18f452 datasheet, and I can't find the directives for PORTS. I'm trying to synchronize the two pic's but its difficult, I need a way to multiplex data correctly. |
|
|
juanodiy
Joined: 07 Sep 2012 Posts: 17
|
|
Posted: Sat Sep 08, 2012 11:47 am |
|
|
Hi, i solved the problem and the pic 2 is multiplexing in the same time as the data arrives, but now i'm trying to increase the sampling time, and when I do that, the multiplexer does not work because the data arrives more faster, and i can' t find the just time for the program works, please HELP,
PIC1
Code: |
#include <18f452.h>
#device adc=8
#use delay(clock=20000000)
#fuses HS,NOWDT
#byte trisa=0x85
#byte porta=0x05
#byte trisc=0x87
#byte portc=0x07
#byte trisb=0x86
#byte portb=0x06
#BYTE TRISD=0X88
#BYTE PORTD=0X08
#include <lcd.c>
int32 x=40,valor=0,freq,valor2=0; //15 x q las demas instrucciones demoran +o- 110 useg en el main
void main()
{
lcd_init();
setup_adc(ADC_CLOCK_DIV_32);// a 32 div , 73 useg en el multiplexor a 8div, aprox 60 us
setup_adc_ports(RA0_RA1_RA3_ANALOG);
trisc=0x03;
lcd_putc("muestreo:");
lcd_gotoxy(1,2);
lcd_putc(" Hz");
while(true)
{
set_adc_channel(0);
delay_us(13);
valor=read_adc(ADC_START_AND_READ);
output_b(valor);
delay_us(x);
set_adc_channel(1);
delay_us(13);
valor2=read_adc(ADC_START_AND_READ);
output_b(valor2);
delay_us(x);
}
}
|
PIC2
Code: |
#include <18f452.h>
#use delay(clock=20000000)
#fuses HS,NOWDT
#byte trisa=0x85
#byte porta=0x05
#byte trisc=0x87
#byte portc=0x07
#byte trisb=0x86
#byte portb=0x06
#BYTE TRISD=0X88
#BYTE PORTD=0X08
#define aumenta input(PIN_a0)
int16 x=73;//73
int8 valor,valor2;
void main()
{
set_tris_b(0xFF);
set_tris_c(0x00);
set_tris_d(0x00);
while(true)
{
valor=input_b();
output_c(valor);
delay_us(x);
valor2=input_b();
output_d(valor2);
delay_us(x);
}
}
|
the time for multiplex in right order is aprox 73 us, but only if the clock of AD conversor is DIV 32, I'm trying to take more samples and i want to multiplex in right order when the AD conversor works at DIV 8
If somebody known how can I do, I'll be grateful |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Sep 08, 2012 3:29 pm |
|
|
You still have all the incorrect #byte statements. Just delete them all.
To keep bad code in your program is a mistake. To use it is also a mistake.
---------------
Your project consists of PIC #1 that collects data and then it sends the
data to PIC #2. The problem is PIC #1 puts the data onto PortB, but
PIC #2 doesn't know if new data has arrived, because there is no
synchronization method used.
You need to think of a synchronization method and do it.
The easiest way would be to use hardware SPI to send the data from PIC
#1. Then in PIC #2, call the spi_data_is_in() function in a loop.
If PIC #2 receives a byte, then call spi_read() to read it. Look at this CCS
example file:
Quote: |
c:\program files\picc\examples\ex_spi_slave.c
|
It shows code that could give you some ideas of how to do PIC #2.
The problem is that I think you are a beginner and I'm not sure if you
can do it. But I think you should try. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Sun Sep 09, 2012 11:40 am |
|
|
As a comment, you are not going to sample the signals at 50000Hz, with this PIC.
Sampling an ADC channel, takes:
Tacq (the time needed for the signal to acquire, and charge the internal capacitor - 13uSec on this PIC).
Plus 12*Tad ADC clock cycles
The fastest legal ADC clock on this PIC is 625KHz.
So an ADC conversion, doing nothing else, not even storing the numbers, takes 32.2uSec. An absolutely fastest conversion rate of just over 31KHz. Reading two channels, each will get half this rate.
You are not going to get even close, without switching to a PIC with a faster ADC. Most of the later chips have ADC's supporting faster Tad clocks, and also faster Tacq times.. The 4520 for example, which is pin compatible with the 452 has a Tacq, of only 2.4uSec, only needs 11 cycles of the ADC clock to perform a conversion, and this is allowed to be over twice the speed, giving a best case conversion time just on 11uSec. Basically 3* as fast....
You need to rethink your design.
Best Wishes |
|
|
juanodiy
Joined: 07 Sep 2012 Posts: 17
|
|
Posted: Sun Sep 09, 2012 5:09 pm |
|
|
First of all, i really appreciate that you have been reading my post. In my country there is not information about this topic, your answers show your knowledge. Thanks very much.
Quote: |
Your project consists of PIC #1 that collects data and then it sends the
data to PIC #2. The problem is PIC #1 puts the data onto PortB, but
PIC #2 doesn't know if new data has arrived, because there is no
synchronization method used.
|
That is exactly the problem. I will check the example and yes, I'm beginner but I like challenges and your help is awesome. I have found the correct #byte statements
Code: |
#byte PORTA=0xF80
#byte PORTB=0xF81
#byte PORTC=0xF82
#byte PORTD=0xF83
#byte PORTE=0xF84
#byte TRISA=0xF92
#byte TRISB=0xF93
#byte TRISC=0xF94
#byte TRISD=0xF95
#byte TRISE=0xF96
|
|
|
|
juanodiy
Joined: 07 Sep 2012 Posts: 17
|
|
Posted: Sun Sep 09, 2012 5:14 pm |
|
|
Ttelmah wrote: | As a comment, you are not going to sample the signals at 50000Hz, with this PIC.
Sampling an ADC channel, takes:
Tacq (the time needed for the signal to acquire, and charge the internal capacitor - 13uSec on this PIC).
Plus 12*Tad ADC clock cycles
The fastest legal ADC clock on this PIC is 625KHz.
So an ADC conversion, doing nothing else, not even storing the numbers, takes 32.2uSec. An absolutely fastest conversion rate of just over 31KHz. Reading two channels, each will get half this rate.
You are not going to get even close, without switching to a PIC with a faster ADC. Most of the later chips have ADC's supporting faster Tad clocks, and also faster Tacq times.. The 4520 for example, which is pin compatible with the 452 has a Tacq, of only 2.4uSec, only needs 11 cycles of the ADC clock to perform a conversion, and this is allowed to be over twice the speed, giving a best case conversion time just on 11uSec. Basically 3* as fast....
You need to rethink your design.
Best Wishes |
Thanks Ttelmah, I did not know that times you are very expert. I want to sample at 16000, I already have proved and it works. My problem is to synchronize the 2 pics, the idea is to make something similar to a telephonic network but only with two channels. I appreciate if you have some information that could help me.
Thanks! |
|
|
juanodiy
Joined: 07 Sep 2012 Posts: 17
|
PSP |
Posted: Sun Sep 09, 2012 10:38 pm |
|
|
I appreciate any information about psp (Parallel Port). I'm trying to recieve data like this way, but it doesn't work.
The code is below:
Code: |
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#byte PORTA=0xF80
#byte PORTB=0xF81
#byte PORTC=0xF82
#byte PORTD=0xF83
#byte PORTE=0xF84
#byte TRISA=0xF92
#byte TRISB=0xF93
#byte TRISC=0xF94
#byte TRISD=0xF95
#byte TRISE=0xF96
int next_in = 0;
int8 valor,valor2;
short data_lost = TRUE;
#int_psp
void psp_isr() {
next_in++;
valor=input_d();
if(next_in==1)
{
output_c(valor);
}
if(next_in==2)
{
output_b(valor);
next_in=0;
}
}
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_psp(PSP_ENABLED);
enable_interrupts(GLOBAL);
enable_interrupts(INT_PSP);
while(true);
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Mon Sep 10, 2012 2:21 am |
|
|
The obvious question is 'how are your sending this'?.
With the PSP, you need a select line to be strobed by the sending device to trigger the transfer.
Effectively your master needs to hold the WR input on the slave device low, and the RD input high, put the byte onto it's output port, and then strobe the CS input low then high. The PSP interrupt occurs when the CS line goes high at the end of the transfer.
A series of comments:
This is going to use a lot of pins. Are you sure you want to do this?. As PCM programmer says, SPI is an alternative. Since this can be clocked at FOSC/4, the byte can be transferred in just 1.6uSec with a 20MHz master clock, and use just three wires.
You are still ignoring the need to _identify_ the bytes. Problem is that unless the two chips wake up exactly synchronised, and data is never missed, you have the potential for the bytes to get swapped. Using SPI, you could use a single other line as a 'A/B' identifier, and change this according to which channel you are sending, allowing the slave device to always 'know' which channel it is receiving. You need to think about this.
You still have the great unwanted 'swathe' of port identifier defines. These are not wanted/needed.
Best Wishes |
|
|
benoitstjean
Joined: 30 Oct 2007 Posts: 566 Location: Ottawa, Ontario, Canada
|
|
Posted: Mon Sep 10, 2012 11:21 am |
|
|
If you want to make your life easier, just use an external CODEC like the PCM1803A from Texas Instruments. You can get the device mounted on a breakout board for 16$USD from Sparkfun electronics. Simply power it, configure the format via two pins and that's it. Plug-in an analog audio signal that is within the chips's specs and the digital output will be your audio, digitized, in whichever format you selected through the configuration pins. Audio quality is outstanding.
The only problem I am running into (I'm upgrading my stuff to circumvent the problem) is that I am using a PIC18F4620 and with a clock of 24.576MHz, I can sample the digitized audio without a problem and store it internally in an array on the PIC but trying to write it to external memory or an external device, even at 8 bits 8 kHz, is too big of a task for the PIC since the PIC must rely on a few signals from the CODEC to be synchronized with the audio. Don't forget that 8 bits @ 8kHz, it's 64 kbps.
The PCM1803 will give you a word clock indicating if the audio is from the left or right channel. And to be synchronized, you need to sample audio by also reading the bitclock which goes from low-to-high everytime a data bit is valid. If you sample the data from one channel only, then you can *maybe* (and that's what I'm trying to figure-out) use the right-channel's time slice (62.5us) to manipulate the data you just sampled from the left channel.... But in order to maintain your audio quality and not have any errors, you need to be perfectly synchronized... therefore you only have 62.5us left to do something with the data before having to read the left channel's data again.
I tried using the A to D on the PIC for audio before and it was going to be quite a difficult task, if not impossible. I even contacted Microchip and they said it would be very difficult and complicated. So instead, I used an external CODEC. It does all the conversion work for you and simply gives you the digitized audio for you to manipulate along with the BCLK and WCLK signals for you to synchronize yourself with the digitized data.
Or, you could simplify your life even more and purchase the audio development kit from Microchip which comes fully functional with a Wolfson audio CODEC interfaced to a PIC24 (I think... or PIC32), an LCD display and all the stuff you need to get your development going.
Good luck. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Mon Sep 10, 2012 1:12 pm |
|
|
benoitstjean wrote: |
Or, you could simplify your life even more and purchase the audio development kit from Microchip which comes fully functional with a Wolfson audio CODEC interfaced to a PIC24 (I think... or PIC32), an LCD display and all the stuff you need to get your development going.
|
I would agree that the PIC24 has a lot more modes on the MSSP that are direct interface compatible with things like I2S and other framed/clocked serial protocols.
The ADC's are faster too. He could easily build a simple codec in a PIC24 and a more complex one in a dsPIC.
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
juanodiy
Joined: 07 Sep 2012 Posts: 17
|
|
Posted: Mon Sep 10, 2012 10:05 pm |
|
|
Ttelmah wrote: | The obvious question is 'how are your sending this'?.
With the PSP, you need a select line to be strobed by the sending device to trigger the transfer.
Effectively your master needs to hold the WR input on the slave device low, and the RD input high, put the byte onto it's output port, and then strobe the CS input low then high. The PSP interrupt occurs when the CS line goes high at the end of the transfer.
A series of comments:
This is going to use a lot of pins. Are you sure you want to do this?. As PCM programmer says, SPI is an alternative. Since this can be clocked at FOSC/4, the byte can be transferred in just 1.6uSec with a 20MHz master clock, and use just three wires.
You are still ignoring the need to _identify_ the bytes. Problem is that unless the two chips wake up exactly synchronised, and data is never missed, you have the potential for the bytes to get swapped. Using SPI, you could use a single other line as a 'A/B' identifier, and change this according to which channel you are sending, allowing the slave device to always 'know' which channel it is receiving. You need to think about this.
You still have the great unwanted 'swathe' of port identifier defines. These are not wanted/needed.
Best Wishes |
Thanks for the information. I was not given the external hardware on PSP. Now I will try to implement SPI for comunication. I hope to count on your help. |
|
|
juanodiy
Joined: 07 Sep 2012 Posts: 17
|
SPI |
Posted: Tue Sep 11, 2012 12:26 am |
|
|
Hi I have changed the code using SPI but it does not work, when I'm trying to simulate the proteus show me a large number of messages, the messages says:
"Stack overflow is forcing device reset" , I suppose is because the data arrives so fast, but what can I do? , use other method?, what is wrong?, I have only 2 pics 18f452, and I'm sure it is possible with this hardware.
i dont know much about SPI, the codes are below, please i need some help with this project, thanks
PIC#1
Code: |
#include <18f452.h>
#device adc=8
#use delay(clock=20000000)
#fuses HS,NOWDT
#byte PORTA=0xF80
#byte PORTB=0xF81
#byte PORTC=0xF82
#byte PORTD=0xF83
#byte PORTE=0xF84
#byte TRISA=0xF92
#byte TRISB=0xF93
#byte TRISC=0xF94
#byte TRISD=0xF95
#byte TRISE=0xF96
#include <lcd.c>
#define MASTER_SS PIN_B2
int32 x=40,valor=0,freq,valor2=0; //15 x q las demas instrucciones demoran +o- 110 useg en el main
void main()
{
lcd_init();
setup_adc(ADC_CLOCK_DIV_32);// a 32 div , 73 useg en el multiplexor a 8div, 60 us
setup_adc_ports(RA0_RA1_RA3_ANALOG);
setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4);
trisc=0x03;
lcd_putc("muestreo:");
lcd_gotoxy(1,2);
lcd_putc(" Hz");
while(true)
{
set_adc_channel(0);
delay_us(13);
valor=read_adc(ADC_START_AND_READ);
output_low(MASTER_SS);
spi_write(valor);
output_high(MASTER_SS);
delay_us(x);
set_adc_channel(1);
delay_us(13);
valor2=read_adc(ADC_START_AND_READ);
output_low(MASTER_SS);
spi_write(valor2);
output_high(MASTER_SS);
delay_us(x);
}
}
|
PIC#2
Code: |
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#byte PORTA=0xF80
#byte PORTB=0xF81
#byte PORTC=0xF82
#byte PORTD=0xF83
#byte PORTE=0xF84
#byte TRISA=0xF92
#byte TRISB=0xF93
#byte TRISC=0xF94
#byte TRISD=0xF95
#byte TRISE=0xF96
int next_in = 0;
int8 valor,valor2;
short data_lost = TRUE;
void main()
{
clear_interrupt(INT_SSP);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
setup_spi(spi_slave | spi_h_to_l | SPI_CLK_DIV_4);
while(true){
if(spi_data_is_in()){
valor=spi_read();
next_in++;
if(next_in==1){
output_b(valor);
}
else{
output_c(valor);
next_in=0;
}
}
}
} |
Thanks to all coments
Last edited by juanodiy on Tue Sep 11, 2012 12:45 am; edited 1 time in total |
|
|
juanodiy
Joined: 07 Sep 2012 Posts: 17
|
|
Posted: Tue Sep 11, 2012 12:39 am |
|
|
Quote: |
The easiest way would be to use hardware SPI to send the data from PIC
#1. Then in PIC #2, call the spi_data_is_in() function in a loop.
If PIC #2 receives a byte, then call spi_read() to read it.
|
Hi PCM programmer, I already do what you say , but it shows that error in proteus, if you can help me I'll be gratefull to you. |
|
|
|
|
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
|