|
|
View previous topic :: View next topic |
Author |
Message |
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
Help: Interfacing with a serial vocoder |
Posted: Sat Nov 04, 2006 5:21 pm |
|
|
Hi:
·I'm working with a vocoder (transforms analog voice into byte streams); the idea is to pick up the data it delivers, and apply some sort of cipher to this data. My problem is the output itself: it is a constant data stream of 11 bytes every 20[ms], at a fixed speed of 9600 bps. The data structure is something like this:
Code: |
t=0 t=20[ms]
[H1] [H2] [ 9 data bytes ] | [H1] [H2] [ 9 data bytes ] ····
|
where [H1] and [H2] are two header bytes, never change.
·The vocoder has 2 ports: one for a handset, one for RS232. If you connect 2 cards, with a handset each one, and a crossover RS232 cable, you get a phone quality conversation. You notice a sync between the cards, because a state LED turns on.
·The problem occurs when I hook up the microcontroller in between (read the data via RX pin, process the data and then send it via TX pin). At first, i'm trying a really trivial "cipher" (XORing each byte with 0x50). Of course this is not really secure, but i've been adapting the RC4 algorithm, and it works fine by itself (i can post the code if anyone wants it).
·This is the code i'm using so far, and the voice quality i get is really bad: the way i see it, i'm losing data frames:
Code: |
#include <18F252.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#int_rda
void serial_isr()
{
char data;
if(kbhit()) //if a char is available
{
data = getc(); //get char
if(data == 0x56) //if char equals header
xbuff = 0; //reset counter
cbuff[xbuff] = data; //store char
xbuff++; //increase counter
if (xbuff == lenbuff) //if buffer is full
flag = 1;
}
}
int const lenbuff = 11; //defines buffer length
int xbuff=0x00; // index: next char in buffer
char cbuff[lenbuff]; // Buffer
int1 flag = 0; // flag indicating full buffer
void inicbuff(void) // Clean buffer
{
int i;
for(i=0;i<lenbuff> b9]
if(flag)
{
for(i=0;i<11;i++)
putc(cbuff[i] ^ 0x50);
inicbuff(); //clean buffer, lower flag
}
}
}
|
·This code didn't work as expected: I lose sync between the cards, meaning the voice gets corrupted. I tried another piece of code, even simpler (or so i thought):
Code: |
#include <18F252.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#int_rda
void serial_isr()
{
char data;
if(kbhit())
{
data = getc();
putc(data^0x50);
}
}
void main()
{
enable_interrupts(global);
enable_interrupts(int_rda);
while(true)
{
}
}
|
·This doesn't work well either. How do i notice? The sync LED blinks in both cards, and of course, the voice quality is terrible.
·As for now, i'm rather confused as what to do next... My guess is that i need a longer buffer, as the PIC may be losing incoming data while it's sending the previous data...
·My main problem is that i can't stop the card from sending data (no flow control), so the PIC tends to "choke" with the incoming data, before it has time to process the previous data.
·Can anyone give some suggestion? As for the hardware, i'm using the PIC18F252 (1536 bits of RAM, 32768 bits of program memory) with a 20 MHz XTAL, and a MAX232 to interface with the vocoder. I wouldn't mind using another PIC as a physical buffer/intermediate data storage, as long as i can process the packets without losing data (meaning voice quality). Delays aren't really important for this applications, but data integrity is.
·Thanks in advance for your help! Best regards,
Fernando.
PD1: The vocoder i'm using is the VC-55 (www.dvsinc.com)
PD2: Sorry if i extended two much...
Last edited by fmartinezs on Sat Nov 04, 2006 5:30 pm; edited 1 time in total |
|
|
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
|
Posted: Sat Nov 04, 2006 5:27 pm |
|
|
Hey, somehow the code got screwed up when posting it...
*The buffer init routine:
Code: |
void inicbuff(void)
{
int i;
for(i=0;i<lenbuff;i++){
cbuff[i]=0x00;
}
xbuff=0x00;
flag = 0;
}
|
*And the main routine:
Code: |
void main()
{
int i;
enable_interrupts(global);
enable_interrupts(int_rda);
while(true)
{
if(flag)
{
for(i=0;i<11;i++)
putc(cbuff[i]^0x50);
inicbuff();
}
}
} |
|
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Sun Nov 05, 2006 1:31 am |
|
|
One simple thing you may want to try is a 10MHz crystal with the H4 fuse to get a 40MHz clock speed.... if your processor is having a hard time with the over head required for your application. One of the RS232 pros will be able to help with you buffer issues (if there really are any....)
John |
|
|
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
|
Posted: Sun Nov 05, 2006 6:12 am |
|
|
Hi. I was wondering about it: Is the pic fast enough (meaning i'd be need a faster clock), or is it losing data? I threw some numbers on the table:
*At 9600 bps a byte (10 bits counting stop and start bits) takes 1.04[ms] in being transfered (bit time: 104[us]).
*At 20 MHz, each instruction should take about 200[ns]. Checking the .lst file, i noticed it took 10 operations to apply the XOR to each byte (the shorter program i posted). That adds about 2[us] of extra delay for each byte, meaning that it should not be enough to lose data...
·Well, that's just numbers anyway. Any comment, correction, sugestion is welcome... |
|
|
Ttelmah Guest
|
|
Posted: Sun Nov 05, 2006 7:49 am |
|
|
It takes typically about 40 instruction times, to 'reach' the interrupt handler routine on a PIC18, with the need to save all the registers first, and check what has caused the interrupt. The getc routine, then polls the UART, to see if the character is ready, and reads the character if it is (probably about another 4 instruction times). This is then transferred to a memory location. The XOR, should only add about two instructions. Then this character is transferred to the output buffer, after checking if the buffer is empty (perhaps seven instructions). Then the chip clears the interrupt flag, and performs a return to the global interrupt handler. This then restores everything saved when it entered the routine, and returns tthe calling code. Say another 40 instructions.
You add a couple of unecessary instruction to this, by calling kbhit first (if the code arrives in the interrupt, it is because 'receive data is available' (this is what INT_RDA handles), so testing kbhit is a waste.
So the code is taking perhaps about 91 instruction times in total. Worse than you are thinking, but still should be fine.
Now, it is always worth addng 'ERRORS' to the RS232 declaration. This will reset the UART if an overrun error takes place. The fact that the UART is not getting hung without this, implies that no overrun is occurring. This adds another couple of instcution times to the getc.
Your main code takes a lot longer. Accessing an array, adds perhaps 10 instruction times. You should also decrement xbuff, in your overrun test, otherwise data could be writing to the location beyond the end of the buffer...
Best Wishes |
|
|
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
|
Posted: Sun Nov 05, 2006 9:39 pm |
|
|
Thanks for your help, Ttelmah. It seems my numbers weren't quite right... i'll remove the kbhit and add the "errors" to the rs232 declaration.
I did a little experiment: a 16F628A in a loop, sending 11 bytes and pausing for 8 [ms], simulating the output of the vocoder; a 16F877 receiving the incoming data, XORing with 0x20, and sending it the XORed data. When i captured the incoming data from the 877 via a PC terminal, i noticed no frames were lost. This is the code i used (very simple stuff):
*for the 628A:
Code: |
#include <16F628A.h>
#fuses INTRC_IO,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOMCLR,NOPUT,NOCPD
#use delay(clock=4000000)
#use rs232(baud=9600, parity=N, bits=8, xmit=PIN_B2, rcv=PIN_B1)
#use standard_io(A)
#use standard_io(B)
void main()
{
int i, data;
data = 65;
while(true)
{
putc(0x56);
putc(0x0F);
for(i=0;i<9;i++)
putc(data);
delay_ms(8);
data++;
if(data == 91)
data = 65;
}
}
|
*For the 877:
Code: |
#include <16F877.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
void main()
{
int data;
while(1)
{
data = getc();
putc(data^32);
}
}
|
·I used 4MHz clocks instead of the 20 MHz i normally use, and no bytes were lost anyway, so i guess the PIC should be able to handle the incoming data from the vocoder. Well, i'll try with the real thing tomorrow... |
|
|
Guest
|
|
Posted: Mon Nov 06, 2006 6:58 am |
|
|
Can you say what chip have you used for the serial vocoder? Thanks |
|
|
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
|
Posted: Mon Nov 06, 2006 7:41 pm |
|
|
Hi. I don't know the details, as i used a integrated card. But there's a lot of info about it on the manufacturer's website: www.dvsinc.com
·In any case, there's a chip that makes the same voice compression, but it requires some extra hardware: the AMBE-2000 (look it up in the same website).
Best regards,
Fernando |
|
|
|
|
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
|