This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Voice signal sampling with ADC and UART transmission

Good evening,

My group and I are working on a project using the TIVA C Series TM4C123GLaunchPad for our university that consist in the following:

  1. Configuring the signal from an electret microphone to the ADC, using analogic steps such as AGC. This step is completely done, giving as a result a perfectly defined signal between 0V and 3.0V at the ADC input, with a bandwith between 200Hz and 4KHz.
  2. Sampling the voice signal with the microcontroller.
  3. Sending the data to the UART and receiving it with MATLAB.

In step 2 is where our problems begin. We tested the code with a function generator, using senoidal signals between 200 Hz and 4KHz. MATLAB graphs show strange results, since for some frecuencies it displays a correct waveform, but for others they are just nonesense. But that's not our answer. The fact is, we are not getting the samples we actually need. We are getting around 40 samples when we need at least 20K samples for a correct voice sampling. It's like our program works extremely 'slow' and we don't know where are we making a mistake. 

For instance, we worked on the idea of storing those ADC samples in a vector and then when the ADC process is complete, send them to the UART, but we actually don't know quite how to do it. What we like to do is to set a time to the ADC to 'listen' and then display the waveform the best it can.

Also, we are asking for some details about how the ADC works, since we read a lot of datasheets but we couldn't realise very well how it works and when do we must read the convertion results.

Our code (made in CCS v5) looks like the following:

************************************************************************************************************************************************

************************************************************************************************************************************************

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"

int main(void)
{
uint32_t ui32ADC0Value[4]; // Variable for getting ADC values.
volatile uint32_t ui32VoiceSample[4]; // Variable for storing ADC0 FIFO values.
uint8_t i = 0; // Loop counter controller.
volatile uint8_t flag = 0; // Flag counter controller.
volatile uint8_t counter = 0; // Timing counter controller.
char d[4]; // Character array for storing ADC Data for TX.


SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ); // Clock Configuration.

SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // Enable Port A Peripheral.
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); // Enable Port E Peripheral.
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // Enable Port F Peripheral.
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3); // LED's as outputs.
GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_4); // Switch 1 as input.
GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU); // Pull-up for Switch 1.

SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); // Enable UART0 Peripheral.

UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,
(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE)); // UART0 Configuration.
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); // PA0 as UART0RX & PA1 as UART0TX.
UARTFIFOEnable(UART0_BASE); // UART0 FIFO Buffer Enable
UARTEnable(UART0_BASE); // Enable UART0.

GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_5); // Pin PE5 as ADC input (CH8).
GPIOPadConfigSet(GPIO_PORTE_BASE, GPIO_PIN_5,GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU); // Pull-up for ADC input.
SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS); // Define ADC Sample Rate as 1MSPS.
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); // Enable ADC0.
ADCHardwareOversampleConfigure(ADC0_BASE,64); // Hardware Oversampling Configuration.
ADCSequenceDisable(ADC0_BASE, 0); // Disable ADC0 before setting it.
ADCReferenceSet(ADC0_BASE,ADC_REF_INT); // Set internal reference as 3V.
ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 0); // Sequence Sampling as 1 (SS1).
ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH8); // Reads from CH8.
ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH8); // Reads from CH8.
ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_CH8); // Reads from CH8.
ADCSequenceStepConfigure(ADC0_BASE, 1, 3, ADC_CTL_CH8|ADC_CTL_IE|ADC_CTL_END); // Reads from CH8 as the last sequence.
ADCSequenceEnable(ADC0_BASE, 1); // Enable ADC0.

while(1)
{
if (GPIOPinRead(GPIO_PORTF_BASE,GPIO_PIN_4) == 0x00) // When SW1 is pressed, the program begins.
{
flag = 1;
counter = 0;
}

if(flag == 0)
{

}
else // Sampling begins.
{
ADCIntClear(ADC0_BASE, 1); // Clear ADC0 Interrupt.
ADCProcessorTrigger(ADC0_BASE, 1); // Trigger ADC Convertion.
while(!ADCIntStatus(ADC0_BASE, 1, false))
{

}

GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 8); // Green LED indicates that the ADC is ACTIVE.
ADCSequenceDataGet(ADC0_BASE,1 , ui32ADC0Value); // Grab the entire FIFO.

for (i = 0; i < 4; i++)
{
ui32VoiceSample[i] = ui32ADC0Value[i]; // Stores the FIFO into the variable.
}

for (i = 0; i < 4; i++)
{
a[3] = ui32VoiceSample[i]%10 + 48; // Convert the first 8 bits to char.
ui32VoiceSample[i] = ui32VoiceSample[i]/10 ;
a[2] = ui32VoiceSample[i]%10 + 48; // Convert the second 8 bits to char.
ui32VoiceSample[i] = ui32VoiceSample[i]/10 ;
a[1] = ui32VoiceSample[i]%10 + 48; // Convert the third 8 bits to char.
a[0] = ui32VoiceSample[i]/10 + 48; // Convert the fourth 8 bits to char.

UARTCharPutNonBlocking(UART0_BASE, d[0]); // Send first character.
UARTCharPutNonBlocking(UART0_BASE, d[1]); // Send second character.
UARTCharPutNonBlocking(UART0_BASE, d[2]); // Send third character.
UARTCharPutNonBlocking(UART0_BASE, d[3]); // Send fourth character.
UARTCharPutNonBlocking(UART0_BASE, '\n'); // Send new line character.
SysCtlDelay(2000000); // System delay.
}

counter ++; // Increment counter.
if(counter == 100) // Counter controls the time the ADC is "listening".
{
flag = 0;
}
}

GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0x00); // Green LED OFF indicates that the program is complete.
}
}

*************************************************************************************************************************************************

*************************************************************************************************************************************************

And our MATLAB scripts looks like the following:

*************************************************************************************************************************************************

*************************************************************************************************************************************************

function Version_2_8(samples)

close all;
clc;
result = (0);

delete (instrfind({'port'},{'COM4'}));
port = serial('COM4');
port.BaudRate = 115200;

fopen(port);
counter = 1;


while counter <= samples
ylim ([0 5.1]);
xlim ([0 salmples]);
ADCvalue = fscanf(port,'%d')';
result(counter) = ADCvalue(1);
stem(result);
drawnow;
counter = counter + 1;
end;

fclose (port);
delete (port);
clear all;

*****************************************************************************************************************

*****************************************************************************************************************

We aprecciate any kind of help or advise, since we are quite new in this topics and we want to learn as much as we can about it. Thank you very much for your time.

  • Hello Luis,

    First of all you need to get rid of the Oversampling.

    ADCHardwareOversampleConfigure(ADC0_BASE,64); // Hardware Oversampling Configuration.

    Secondly the entire operation is being done in processor trigger mode and the computation being done after that will incur CPU penalty before it reaches the sampling again. The right thing to get a constant sampling is to have a timer giving periodic trigger to the ADC and the CPU reading the samples out while the next set of conversions are happening or get scheduled.

    Regards
    Amit
  • A few comments

    1. Indent your code properly.
    2. SysCtlDelay(2000000);  <--- Why are you surprised it's running slowly with this in your main loop?
    3. UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200, <--- work out your bandwidth requirements
    4. a[0] = ui32VoiceSample[i]/10 + 48; // Convert the fourth 8 bits to char. <--- I don't think this will even compile.  I didn't see a defined anywhere.  If that is the case then I'd suggest cutting and pasting your actual code.
    5. Amit's point is well made

     

    Robert

  • Re: Amit's & Robert's analysis/comments...

    Amit "stole" my "misuse of HW ADC averager" (shut that cb1 post down) while Robert made extra code-review effort.

    Good for both of those caring, well designed responses.

    Yet - might an elephant lurk - this/many other classrooms?

    Where are the course leads/instructors?  Enough basics have been missed/mis-applied - makes one question course design/management!

    Are the "MCU Forums" now the real (effective) classrooms?   And unpaid ones?    Is this proper?   Who determines?

    May deserve (some) thought/consideration.   (or business as usual - ask no questions - take no prisoners - and endlessly read precision, "Does not Work!")