Board index › Products › Audio Codec Shield

Serial comm with Maple

20 posts · 24811 views

Serial comm with Maple

by chipaudette » Mon May 07, 2012 18:51 UTC
I've been using the Audio Codec Shield with an Arduino as a ADC and DAC for my PC for some lab work. I was streaming the data back to the PC over the Arduino's regular USB serial link. This worked fine but I decided that I wanted to do some real-time calculations on the Arduino and it didn't have enough horsepower...so I bought a Maple.

When I open up the Audio Codec Shield example program (sine_generator) from LeafLabs, the first thing that I see is that they disable the USBSerial saying that "conflicts with the codec".

Um, no serial? Really? That's a pretty big loss of functionality! It also makes debugging pretty hard. This also prevents me from using it as an ADC for my PC.

Are there any workarounds for this? The LeafLabs comment in the code also says that "a different operating mode which allows both is in the works". Has there been any progress?

Chip

Re: Serial comm with Maple

by chipaudette » Mon May 07, 2012 19:19 UTC
Oh, and because the USBSerial is disabled in order to use the Codec Shield, you can't upload new code to the Maple from its IDE without putting the Maple into bootloader mode...which requires you to pull off the shield and press the magic combination of buttons.

This is quite a pain, it really slows me down, and it increases the likelihood bending pins on the shield.

Any knowledge or workarounds would be *greatly* appreciated!

Chip

Re: Serial comm with Maple

by guest » Tue May 08, 2012 20:15 UTC
hello chip
sorry that i did not catch your first post

we havent recieved any updates from leaflabs
in regards to the USB problems
and youre right
it is quite a pain to have to reset on every upload

i will ask leaflabs to see if they can look at it
but if you want to post over at the leaflabs forums
there might be other users who have looked at this issue

Re: Serial comm with Maple

by guest » Tue May 08, 2012 20:25 UTC
another thing to try
is to just comment out the usb code
and see what happens
if i recall correctly
the reason why it is there is because the usb makes audio glitches
but maybe it will be ok

Re: Serial comm with Maple

by guest » Thu May 17, 2012 05:51 UTC
i was giving this some more thought today
and i think the problem with usb
is that it could only be blocked for so long
before it crashed the whole micro
and the interrupt routine for the codecshield
takes up all the processing time

one way around this
is to change what happens where
if only the first data transfer happened in the interrupt
and the rest happened in the main loop
it would block the usb
and usb would function fine
although this would cause the audio data
to not be transferred at exactly the right time
but im not sure how big of a problem that would be

Re: Serial comm with Maple

by vaxon » Wed Jun 13, 2012 00:43 UTC
I'm not getting any real serial data back from the Arduinio. I tried stripping it down to :

ISR(TIMER1_COMPA_vect, ISR_NAKED) {
AudioCodec_data(&left_in, &right_in, left_out, right_out);
output=
reti();

With " Serial.println(out1);" in the loop and It just glitches out.

What was your test setup, chip?

Re: Serial comm with Maple

by guest » Wed Jun 13, 2012 03:02 UTC
the maple has different issues than the arduino

try changing the interrupt routine to:

ISR(TIMER1_COMPA_vect) {
}

this will have it push all the data onto the stack

the other thing to try
is to re-enable timer0
as the last line in your setup() put
TIMSK0 = 0x01;

Re: Serial comm with Maple

by guest » Thu Jun 14, 2012 06:12 UTC
i just tried a number of variants
and i couldnt get the serial to talk
i will have to dig deeper to find out why
but i think the codec interrupt might be blocking for too long
or vice versa

i got it to transfer a few bytes
and it caused clicks when doing so

im working on a rewrite of the header file
that will allow for a different programming setup
and it might alleviate this problem

alternatively
a rewrite of the serial code would probably make it work
it depends upon what you want to do
streaming data out of the arduino would be pretty easy
just write UDR0 = byte;

ive got that working without any glitches

heres what you have to do:
1. change the interrupt routine to:
ISR(TIMER1_COMPA_vect) {

2. get rid of the reti; at the end of the interrupt routine
3. reinstate TIMER0 by writing TIMSK0 = 0x01 at the end of the setup routine
4. call Serial.begin() in the setup routine
5. call UDR0 = (byte of your data) when you want to send something

there isnt any flow control in this scheme
but delay() is now re-enabled
so you can just space it so it wont collide

Re: Serial comm with Maple

by clee » Fri Jul 06, 2012 11:43 UTC
It's my understanding that USB needs to be stopped when using the maple because the maple stm32 microcontroller is actually servicing the USB communication. libmaple does this using interrupts which glitch the audio processing. The arduino actually has a second microcontroller from FTDI just for USB input so that the main MCU doesn't have to worry about USB protocol servicing.

One option for you to get rapid serial communication is to use a FTDI breakout board or USB to serial cable and connect to one of the several serial interfaces on the maple. Lot's of manufacturers make these available (eg http://www.sparkfun.com/products/9718). I need to look again at the maple to see if it needs 5V or 3.3V serial input.

I think it is even possible to make it so the cable triggers a hardware reset of the maple---though I haven't done it myself.

I just got my audio codec shield so I might try this approach myself. I already have a few of these FTDI USB-to-serial gadgets.

Re: Serial comm with Maple

by guest » Sat Jul 07, 2012 00:05 UTC
that sounds like a good idea
let us know how it goes

i think there will still be trouble with bootloading
as the bootload code wants to read from the onboard usb

Re: Serial comm with Maple

by clee » Sat Jul 07, 2012 14:31 UTC
The approach of communicating via a FTDI breakout to the maple while using the audio codec shield appears to work, at least with a simple example.

I added code to the sine generator example to write to "Serial3" at up to 1500000 baud this morning. The tone still sounds glitch free.

Here's the code with a little explaination of the connections.

/*
sine_generator_plus_serial3.pde (MAPLE)

Based upon sine_generator in the Open Music Labs AudioCodec_Maple examples, the code adds only writing to USART Serial3 while audio_codec is running too. It just outputs a count of the main loop iterations every N steps while an interupt generates the sine tone outupt. -Chris Lee-Messer

guest openmusiclabs 7.13.11
this program creates a sinewave of variable frequency and
amplitude, presented at both left and right outputs. there
isnt any interpolation, so you only get 256 discrete frequencies
across the span of 44Hz to 10kHz.


Hardware connections
--------------------
From the the maple documentaiton the USART Pin Map
         Tx     Rx      Ck      cts     rts
Serial3	D29	D30	D31	D32	D33
(this also applies to the Maple RET6 edition)
These pins are also listed as being ***5V tolerant***


I chose Serial3 because these pins are on the 2x8 header "EXT" block which aren't
connected to the audio codec shield.


So I connected 3 wires to my FTDI basic board:
   D29 (Tx) to the Rx on the FTDI basic board
   D30 (Rx) to the Tx on the FTDI basic board
        GND to GND on on the FTDI basic board

License: what every Open Music Labs published the Audiocodec files under

	
*/

// setup codec parameters
// must be done before #includes
// see readme file in libraries folder for explanations
#define SAMPLE_RATE 44 // 44.1kHz sample rate
#define ADCS 2 // use both ADCs

// try faster 9600, 19200, 14400, 38400, 57600, 56000,
// 115200, 128000, 230400,460800, 153600, 256000,921600
// the FTDI 232R datasheet says it can go to 3 Mbaud
#define BAUDRATE 1500000

#define N_SENDSERIAL 100 // send a serial value every N steps through the loop   
// include necessary libraries
// note the Maple library
#include <AudioCodec_Maple.h>

// create data variables for audio transfer
// even though there is no input needed, the codec requires stereo data
// note the uint16 typedef, there is no "unsigned int16" type
int16 left_in = 0; // in from codec (LINE_IN)
int16 right_in = 0;
int16 left_out = 0; // out to codec (HP_OUT)
int16 right_out = 0;

// create variables for ADC results
// it only has positive values -> unsigned
uint16 mod0_value = 0;
uint16 mod1_value = 0;

// create sinewave lookup table
// note the int16, ints are 32b in Maple land
int16 sinewave[] __FLASH__ = {
  // this file is stored in AudioCodec_Maple.h and is a 1024 value
  // sinewave lookup table of signed 16bit integers
  // you can replace it with your own waveform if you like
  #include <sinetable.inc>
};
uint16 location; // lookup table value location
unsigned int g_count = 0;

void setup() {
  Serial3.begin(BAUDRATE);
  SerialUSB.end(); // usb conflicts with the codec in this mode
                   // a different operating mode which allows both
                   // is in the works
  // setup codec and microcontroller registers
  AudioCodec_init(); // call this last if you are setting up other things
}

void loop() {
  // while (1); // reduces clock jitter

  if (!(g_count % N_SENDSERIAL)) {
     Serial3.println(g_count);
  }
  g_count++;
}

// timer1 interrupt routine - all data processed here
void AudioCodec_interrupt() {

  // &'s are necessary on data_in variables
  AudioCodec_data(&left_in, &right_in, left_out, right_out);
  
  // create some temporary variables
  // these tend to work faster than using the main data variables
  // as they arent fetched and stored all the time
  int16 temp1;
  
  // create a variable frequency and amplitude sinewave
  // fetch a sample from the lookup table
  temp1 = sinewave[location];
  // step through table at rate determined by mod1
  // use upper byte of mod1 value to set the rate
  // and have an offset of 1 so there is always an increment.
  location += 1 + (mod1_value >> 8);
  // if weve gone over the table boundary -> loop back
  // around to the other side.
  location &= 0x03ff; // fast way of doing rollover for 2^n numbers
                      // otherwise it would look like this:
                      // if (location >= 1024) {
                      // location -= 1024;
                      // }
  
  // set amplitude with mod0
  // multiply our sinewave by the mod0 value
  // since it returns a 32bit value it needs to be scaled with ">> 16"
  temp1 = (temp1 * mod0_value) >> 16;
  left_out = temp1; // put sinusoid out on left channel
  right_out = -temp1; // put inverted version out on right chanel

  // get ADC values
  // & is required before adc variables
  AudioCodec_ADC(&mod0_value, &mod1_value);


  // you dont need to reti() with Maple
}

Re: Serial comm with Maple

by guest » Sat Jul 07, 2012 20:23 UTC
thats awesome
glad to hear its working
a number of people have asked how to get the codec data into the computer
and this looks like a pretty good way

Re: Serial comm with Maple

by clee » Tue Jul 10, 2012 00:44 UTC
Yes, the serial ports seems like a pretty good option.

I have done a few tests and with a baud setting of 2000000, a simple python test client can transfer ra 1024 16-bit ints is about 13.5ms while the maple+audio codec shield continues to play the sine wave tone. That's about 151 kB/s including the overhead for my not-very-efficient python code as compared to the theoretical, no-overhead-max of 250 kB/s.

At the next speed above that, 30000000, the connection can't be made, which makes sense given that 2.25 Mb/s is the spec sheet limit on some of the maple's USARTs.

I'm pretty sure things could be faster. I would think options include looking at using dma or use of the other SPI interface (18 Mb/s) might be the way to go.

I put my test doodles in a repo if people would like to look (the sketch is called "upload_play"):
https://bitbucket.org/cleemesser/maple-stm32-learn/src/428f89184565/upload_play

Re: Serial comm with Maple

by guest » Fri Jul 27, 2012 23:38 UTC
so i did some more digging into the usb problem

the initial problem had to do with the fact
that the maple usb interrupt can not be blocked for more than a few microseconds
which the audiocdec library clearly does quite frequently

so i rewrote the audiocodec library to only take a fraction of a microsecond in the interrupt
and this allowed the maple usb to function again
but now the maple usb interrupt is blocking the audiocodec interrupt
and the data is not getting clocked out to the codec at regular enough intervals
this gives audible clicks in the playback data

im going to look at a few things on a scope
but i think this is the best the maple can do for usb
until the maple usb library is rewritten

Re: Serial comm with Maple

by diydsp » Sat Jul 28, 2012 00:52 UTC
clee wrote:Yes, the serial ports seems like a pretty good option.

I have done a few tests and with a baud setting of 2000000, a simple python test client can transfer ra 1024 16-bit ints is about 13.5ms
...
I put my test doodles in a repo if people would like to look (the sketch is called "upload_play"):
https://bitbucket.org/cleemesser/maple-stm32-learn/src/428f89184565/upload_play


dude, that is awesome work.

BTW, I might be attaching to that serial port for other purposes, such as modifying the timeout in the bootloader. Have you got any references for how to attach, e.g. an FTDI 3V serial port to the Maple?

Re: Serial comm with Maple

by clee » Sat Jul 28, 2012 04:24 UTC
I don't have too much experience with this sort of thing. What I have done after I to look up the correct pins numbers in the documentation http://leaflabs.com/docs/hardware/maple.html#gpio-information, is to run short jumper cables like so:

For a basic two-way communication setup there are 3 wires to hook up :

maple ----- ftdi
Tx ----- Rx
Rx ----- Tx
Gnd ----- Gnd


As far as I can tell, for reliable transmission at higher speeds it may be necessary to use flow control. For to support this in hardware this requires addional connections:
maple      ftdi
Tx ----- Rx
Rx ----- Tx
Gnd ----- Gnd
RTS ----- CTS
CTS ----- RTS


I'm currently working out the code to do the flow control. There is an example in the ST peripheral library examples. I haven't found RTS/CTS flow control in libmaple yet and I'm not sure how much is handled by the USART itself in hardware and how much one needs to modify one's code to use RTS/CTS.

Re: Serial comm with Maple

by guest » Tue Jul 31, 2012 01:08 UTC
im getting closer to having the usb working
with the help of the leaflabs folks
i found a way to have nested interrupts
placing this in setup gives timer4 priority

  SCB_BASE->AIRCR = 0x05FA0300;
  nvic_irq_set_priority(NVIC_TIMER4, 0);
  nvic_irq_set_priority(NVIC_USB_HP_CAN_TX, 15);
  nvic_irq_set_priority(NVIC_USB_LP_CAN_RX0, 15);
  nvic_irq_set_priority(NVIC_USBWAKEUP, 15);


i then created a buffer for the data
and it greatly reduces the clicks
but they are not all gone yet

ultimately i think the uart trick is way easier
and a lot less computationally intensive
the usb handler wastes a lot of time

the main reason i want to get usb working
is so i dont have to hit reset every time i load code

Re: Serial comm with Maple

by guest » Tue Jul 31, 2012 01:38 UTC
ok this seems to work

/*
sine_generator.pde (MAPLE)
guest openmusiclabs 7.30.12
test program for usb communication with codecshield
plays back a glitch free audio stream while usb is active
*/

// setup codec parameters
// must be done before #includes
// see readme file in libraries folder for explanations
#define SAMPLE_RATE 44 // 44.1kHz sample rate
#define ADCS 2 // use both ADCs

// include necessary libraries
// note the Maple library
#include <AudioCodec_Maple.h>
#include <scb.h> // for setting the interrupt priorities

int16 left_in = 0; // in from codec (LINE_IN)
int16 right_in = 0;
volatile int16 left_out = 0; // out to codec (HP_OUT)
volatile int16 right_out = 0;
volatile int16 waittimer = 0;

uint16 mod0_value = 0;
uint16 mod1_value = 0;

int16 buffer[8];
volatile uint8 buffertop = 0;
volatile uint8 bufferofset = 2;

int16 sinewave[] __FLASH__ = {
  #include <sinetable.inc>
};
uint16 location; // lookup table value location


void setup() {
  // setup codec and microcontroller registers
  AudioCodec_init(); // call this last if you are setting up other things
  SCB_BASE->AIRCR = 0x05FA0300;
  nvic_irq_set_priority(NVIC_TIMER4, 0);
  nvic_irq_set_priority(NVIC_USB_HP_CAN_TX, 15);
  nvic_irq_set_priority(NVIC_USB_LP_CAN_RX0, 15);
  nvic_irq_set_priority(NVIC_USBWAKEUP, 15);
}

void loop() {
  while (1) { // reduces clock jitter
  while (waittimer == 0);
  while (!(SPI1_BASE->SR & (1 << SPI_SR_RXNE_BIT))) { // wait for data to arrive
  }
  left_in = SPI1_BASE->DR; // recieve left data
  while (!(SPI1_BASE->SR & (1 << SPI_SR_RXNE_BIT))) { // wait for data to arrive
  }
  right_in = SPI1_BASE->DR; // recieve right data
  waittimer = 0;
  while (bufferofset < 6) {
    int16 temp1;
    temp1 = sinewave[location];
    location += 1 + (mod1_value >> 8);
    location &= 0x03ff;
    temp1 = ((temp1 * mod0_value) >> 16) & 0xfffe;
    buffer[(buffertop + bufferofset)&0x07] = temp1;
    bufferofset++;
  }
  AudioCodec_ADC(&mod0_value, &mod1_value);
  }
}

// timer1 interrupt routine - all data processed here
void AudioCodec_interrupt() {
  left_out = buffer[buffertop];
  GPIOA_BASE->BSRR = 0x00000010; // set ss high
  SPI1_BASE->DR = left_out; // send out left data
  asm volatile ("nop"); // delay for appropriate timing
  asm volatile ("nop");
  asm volatile ("nop");
  asm volatile ("nop");
  asm volatile ("nop");
  asm volatile ("nop");
  asm volatile ("nop");
  asm volatile ("nop");
  asm volatile ("nop");
  GPIOA_BASE->BSRR = 0x00100000; // set ss low
  right_out =  left_out;
  buffertop++;
  bufferofset--;
  buffertop &= 0x07;
  while (!(SPI1_BASE->SR & (1 << SPI_SR_TXE_BIT))) { // wait for data to be sent
  }
  SPI1_BASE->DR = right_out; // send out right data
  waittimer = 1;
}


if others use it and it seems reasonable
i will write it up as an alternate library function

Re: Serial comm with Maple

by clee » Sun Aug 05, 2012 05:52 UTC
Thank you for the USB code. I'll give it a try. This also gives helped me learn about how the interrupt priorties are set in the libmaple way of doing things.

I've noticed reliability issues with the using the ft232R based breakout naively. The basic tx/rx connection works pretty well at 2Mb/s but eventually there is a transfer failure. It's unpredictable but usually it makes it about 70-100Mb of transfer and it fails. Because it is rare, I haven't pinned down the exact cause of the problem. I need to figure out if I can read error flags from the ftdi interface. There's probably a system that I need to google for.

One guess about the problem is that the USB bus on my linux laptop is occasional off serving something else occasionally and causing a delay in accepting data in the middle of the transfer from the maple---bits overrun the small buffers in the ft232 occurs and the data stream is corrupted.

I'm trying out using the ft2232H instead which has 4k buffers built in. So far I've repeatedly transferred 2kB at about 180-190 kB/s (using the 2,000,000 baud rate seting) for about 2 hours without an error. :-)

[got it from dangerous prototypes http://dangerousprototypes.com/docs/FT2 ... kout_board]

Re: Serial comm with Maple

by clee » Wed Aug 15, 2012 20:15 UTC
Update: Things are going well using the USART. Both the FT232RL and the FT2232H based breakouts are working well and consistently giving ~186kB/s with bit rates of 2Mb/s in my test code. My reliability issues initially resolved with using hardware flow control and I've started adding to libmaple to make RTS/CTS flow control available in libmaple. [See http://forums.leaflabs.com/topic.php?id ... post-12454 and https://github.com/cleemesser/libmaple]

However, I think that at least part of my reliability issue was due to a boarderline bad jumper cable, because after a recent cleanup and change of many of the wires, I can't reproduce the error anymore. I really need to get a logic analyzer and my oscilloscope working again.

The next step is to try SPI with its 18Mb/s bandwidth. I've started trying out the olimex maple clone as well, in part, because it has a nice angled UEXT connector which makes USART3 and SPI available even when the audio codec board is mated to the maple.