Select Page

Real-time Audio Frequency Spectrum Analyzer on Beaglebone black

Design Requirement

This project builds a remote real-time audio spectrum analyzer to sample audio frequency signals using Beaglebone black Wireless. The spectral/time domain results can be viewed from any remote terminal over the network.

Setup with Arbitrary Function Generator as Source

Resources Required

Hardware

  1. Beaglebone Black Wireless (BBBW)
  2. Signal Source to generate an audio signal
  3. Oscilloscope to check the input before feeding into BBBW

Software

  1. TI Processor SDK Linux AM335x [[1]]
  2. minicom
  3. gnuplot
  4. Linux Kernel Version : 4.14.108-ti-r119 (Tested)

Project Description

Setup with Arbitrary Function Generator as Source

BBBW Outputs plotted in real-time from a remote machine

  • Analog signal from an external source (0V < Vin < 1.8V) is fed to analog channel input of BBBW Pin P8.36
  • The on chip ADC peripheral samples the signal which is controlled by the Programmable Real-time Unit Interconnect Subsystem (PRU-ICSS) or PRU in short.
  • The user-space application runs on BBBW which in turn initiates the PRU and acquires the raw ADC outputs for further processing
  • The user-space application sends the processed time-domain and the frequency domain outputs to gnuplot for display.

PRU-ICSS : Programmable Real-time Unit Interconnect Subsystem

Impetus

High performance does not guarantee real-time performance. The onboard AM3358 controller ADC can sample at a rate of 200 ksps. The ADC linux driver provides a SysFS interface to read the ADC outputs from a file. However, using this method, one sample cannot be read faster than 12ms, which effectively limits the maximum sample rate to 1/12ms ~ 83 Hz. Also, the duration between successive samples is variable and largely depends on the current operating system workloads, which reduces the accuracy of the FFT algorithm thereby impacting the overall system performance. Therefore, it makes makes more sense to control a peripheral with a deterministic, dedicated processor rather than a general purpose ARM core running an OS.

Block Diagram of AM3358 SoC depicting the layers of interconnection buses and the PRU Source: https://trainin

PRU Subsystem

  • Consists of dual, independent 32-bit RISC cores (Programmable Real-Time Units, or PRUs), data and instruction memories, internal peripheral modules, and an interrupt controller. Source:[[2]]
  • Runs at 200 MHz (No pipelining)
  • Execution Unit supports arithmetic logic instructions, load-store instructions and control transfer instructions.
  • With the exception of read instruction , the PRU executes all instructions in a single cycle.
    • Latency Figures for PRU Access-
      • Instruction RAM :1 Cycle
      • DRAM : 3 Cycles
      • Shared DRAM : 3 Cycles
  • PRU is added as a node on the L3 interconnect.
  • PRU has its own local interconnect to enable ultra-low latency and deterministic access times to its memories and peripherals.
  • PRU also has access to all system peripherals

Controlling the PRU

  • Disable ADC Driver for ARM Host : Since PRU is an independent processor which competes with ARM Host for accessing the peripherals, the ADC peripheral has to be disabled in the ARM Host. This is done by disabling the tscadc peripheral in the device tree source file as shown in below-

tscadc: tscadc@44e0d000 {

           compatible = "ti,am3359-tscadc";
           reg = <0x44e0d000 0x1000>;
           interrupts = <16>;
           ti,hwmods = "adc_tsc";
           status = "disabled";
           dmas = <&edma 53 0>, <&edma 57 0>;
           dma-names = "fifo0", "fifo1";
           tsc {
               compatible = "ti,am3359-tsc";
           };
           am335x_adc: adc {
               #io-channel-cells = <1>;
               compatible = "ti,am3359-adc";
           };
       };
    • After the above modification the dts file has to re-compiled using dtc (device-tree-compiler)
    • Also include the following line in /boot/uEnv.txt
disable_uboot_overlay_adc=1
  • Load PRU firmware:Linux drivers allow the PRU firmware to be loaded into the PRU’s instruction memory from the Linux user space through SysFS interface.
  • initialize ADC from PRU: Required to be done by the PRU firmware since ADC device driver in the Linux kernel is now disabled.

Software Architecture

Software Architecture

PRU Firmware

  • Written in C language
  • Basic code framework is available in PRU-Software_support_package” [[3]]
  • Pseudo-code for the firmware is shown below
adc_init()
{
	Enable ADC Clock;
	Disable ADC Module so that it can be configured
	Configure ADC Step configuration registers
	Mode = Continuous
	No. Of samples to be averaged = 0
	Sample Delay = 0
Note: Depending on the quality of the signal monitored and the maximum frequency requirements, these parameters may be adjusted.
	Enable ADC module;
 
}
 adc_read()
{
	for i:0-->3
		If ADC_FIFO is not empty, read the ADC_FIFO and store it in buffer[i].
	return average( buffer[2] + buffer[3] );
}
adc_firmware_main()
{
        adc_init();
	Initiallize RPMsg message_structure;
	Wait for interrupt from ARM through RPMSg;
	for i:0->NO_OF_SAMPLES+10
		captures[i]= read_adc();
	copy the last NO_OF_SAMPLES samples into the RPMSg message reply;
}

User Space Program

main()
{
	driver_init();
	pthread_create(read_ADC_channel);
	pthread_create(processing);
	join;
}
void* read_ADC_Channel()
{
	Pass an RPMsg to PRU to initiate data acqisition;
	Wait for response from PRU;
	extract and return voltages;
}
void* processing()
{
	send_voltages_to_gnu_oscilloscope_pipe;
	compute_fft();
	send_fft_data_to_gnu_spectrum_analyzer_pipe;
}

FFT

  • 128 point Radix-2 DIT FFT

Functions

short *  bit_reversal() // To get the bit reversed order of inputs.
short * twiddle_calc(int16_t R,int16_t Ni) // To calculate twiddle factors of a butterfly.
short * butterfly(int16_t i1_re,int16_t i2_re,int16_t i1_im,int16_t i2_im, int16_t w_re,int16_t w_im)   // To calculate output of butterfly given twiddles and other inputs.
short * myfft(short * voltages) // complete fft code.

Inter Process Communication

  • Semaphores
    • Voltage Buffer[128]

      is a global buffer and access to it is controlled by Semaphore

  • Pipes
    • Time domain and frequency domain outputs are sent through separate pipes to 2 gnuplot process

Inter-process Communication Scheme

PRU Linux Driver

RPMsg

  • RPMsg is a method of passing messages and data between the PRU cores and the ARM core running Linux in Texas Instruments’ Sitara devices
  • RPMsg is enabled by a combination of remoteproc and the virtio framework.

PRU Software Support Package

The PRU Software Support Package provides support for the PRU-ICSS Subsystem in AM335x, AM437x, AM57xx, and K2G devices. This package contains:

  1. Support for ARM<->PRU interaction via remoteproc and rpmsg Linux drivers
    1. remoteproc supports basic control functions such as firmware load, start/halt, simple debug, and interrupt managing
    2. rpmsg supports message passing
  2. Basic firmware examples showing simple functionality
  3. Register header files for easy register programming
  4. Library/API for controlling vrings (used for rpmsg)

Enabling PRU Support in Kernel

  • Menu config
    • Disable ADC in Device Tree
BBBW Outputs plotted in real-time from a remote machine

Specifications Achieved

  1. Sampling Frequency : 62 KHz
  2. Frequency Range: 500 Hz – 31 KHz
  3. Frequency Resolution: 500 Hz

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Future Improvisations

  • Increasing Range : Increase the size of the RP_MSG_BUFFER . Current value = 512B, It needs to be increased
  • Support for lower frequency

Challenges

  1. Problem with ADC Raw output
    • There are two modes of operation – One-shot Mode and Continuous Mode
    • In one-shot mode, it was observed that every alternate sample shows 1.7V(ADC_Count = 3900).
    • To overcome this, a time-gap of around (40,000 PRU Cycles = 200 us) had be provided in the firmware. This yielded a max.sampling frequency of 2.6 KHz
    • In Continuous mode, it was observed that almost all the reading were incorrect. Out of 128 readings, only 2 samples showed correct readings!
    • However, the sample numbers (out of these 128 samples) which yielded correct results were consistent – Sample# 2 and 87 OR Sample#3 and 88.
    • The firmware was then modified to read 128 samples in continuous mode and average samples 2,3,87,88 to generate one sample. And this process was repeated 128 times.
    • However, the sampling frequency was still too low
    • So, to gain sampling frequency, instead of acquiring 128 samples in continuous mode, only 4 samples are acquired. Averaging is done to samples 2 and 3 (Sample number starts from 0). And this process is repeated for 128 times.
    • With this, there was again of 30x in sampling frequency without any compromise on the accuracy
  1. Kernel Changes
    • A new kernel source with remote_proc enabled is not functional. The remote_proc driver fails to open and this could not be debugged
    • Because of this, the Kernel change to increase the RPMSG_BUFFER_SIZE could not be increased beyond 512B thereby imposing a minimum input frequency and resolution