Sending MSP432’s ADC samples over “backchannel” UART

This is very cool. The MSP‑EXP432P401R LaunchPad™ [ slau597 ] supports an additional UART through XDS110 just for debug / sending data over to a PC. Even better:

The backchannel UART eUSCI_A0 is independent of the UART on the 40-pin BoosterPack connector eUSCI_A2.

Not that I am using any BoosterPacks, but that is very cool that we can keep serial writes to a computer separate from other things the MCU might be doing.

Now, the online community has written a printf function using this UART:

[ 43oh tutorial ] [ Sam Lewis’s note ]

Here’s a link to the CCS guide for MSP432 as that might also come in handy:

[ slau575b ]

And the resource explorer example for the making ADC conversions based on interrupts from Timer A:

[ adc14_single_conversion_repeat_timera_source.c ]

On my end, the printf and adc14 examples are working individually. I changed the baud rate to 57600 and printed out an unsigned 32 bit counter to PuTTy just to get an idea of how much data I could get through. It will probably be an overkill for just sampling ECG at 250 Hz, but I am sure it will work.

Here’s the slightly edited call to printf:

/* DriverLib Includes */
#include "driverlib.h";

/* Standard Includes */
#include <stdint.h>;
#include <stdbool.h>;
#include <printf.h>;

/* UART Configuration Parameter. These are the configuration parameters to
* make the eUSCI A UART module to operate with a 9600 baud rate. These
* values were calculated using the online calculator that TI provides
* at:
*http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html
*/

// setting the baud rate to 57600 instead of 9600. It will easily support 250 Hz. 9600 should too, PuTTy is just printing slow.
// http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html
// use eUSCI, 12M clock
const eUSCI_UART_Config uartConfig =
{
EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
13, //78, // BRDIV = 78
0, //2, // UCxBRF = 2
37, //0, // UCxBRS = 0
EUSCI_A_UART_NO_PARITY, // No Parity
EUSCI_A_UART_LSB_FIRST, // MSB First
EUSCI_A_UART_ONE_STOP_BIT, // One stop bit
EUSCI_A_UART_MODE, // UART mode
EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION // Oversampling
};

int main(void)
{
/* Halting WDT */
MAP_WDT_A_holdTimer();

/* Selecting P1.2 and P1.3 in UART mode */
MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);

/* Setting DCO to 12MHz */
CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_12);

/* Configuring UART Module */
MAP_UART_initModule(EUSCI_A0_MODULE, &uartConfig);

/* Enable UART module */
MAP_UART_enableModule(EUSCI_A0_MODULE);

MAP_Interrupt_enableMaster();

/* Initialize values to display */
//char *s = "printf test";
//char c = '!';
//int i = 0;//-12345;
unsigned u = 0;//4321;
//long unsigned n = 1098765432;
//unsigned x = 0xABCD;

while(1)
{
//printf(EUSCI_A0_MODULE, "String %s\r\n", s);
//printf(EUSCI_A0_MODULE, "Char %c\r\n", c);
//printf(EUSCI_A0_MODULE, "Integer %i\r\n", i);
////printf(EUSCI_A0_MODULE, "%i\r\n", i);
//printf(EUSCI_A0_MODULE, "Unsigned %u\r\n";, u);
printf(EUSCI_A0_MODULE, "%u\r\n", u);
// printf(EUSCI_A0_MODULE, "Long %l\r\n", l);
//printf(EUSCI_A0_MODULE, "uNsigned loNg %n\r\n", n);
//printf(EUSCI_A0_MODULE, "heX %x\r\n", x);
u++;
}
}

I set the debug mode to release and set the optimizer to its max level. Lots of interesting advice popped out for setting pins to reduce current draw, and for replacing the while loop’s (for debugging) in TI’s .cmd file with timer modules.

The next step is to integrate the adc14 and printf codes. The simplest way of copy-paste combining the modules and commenting out irrelevant  lines works for a really slow rate, and I changing the comparator value (16000) isn’t really affecting anything. So I need to read the manual and find out what’s going on.

/*
* -------------------------------------------
* MSP432 DriverLib - v2_20_00_08
* -------------------------------------------
*
* --COPYRIGHT--,BSD,BSD
* Copyright (c) 2014, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot;
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* --/COPYRIGHT--*/
/*******************************************************************************
* MSP432 ADC14 - Single Channel Continuous Sample w/ Timer_A Trigger
*
* Description: In this ADC14 code example, a single input channel is sampled
* using the standard 3.3v reference. The source of the sample trigger for this
* example is Timer_A CCR1. The ADC is setup to continuously sample/convert
* from A0 when the trigger starts and store the results in resultsBuffer (it
* is setup to be a circular buffer where resPos overflows to 0). Timer_A is
* setup in Continuous mode and a Compare value of 16000 is set as the
* compare trigger. Once the Timer_A is started, after 0.5s it will trigger
* the ADC14 to start conversions. Inside the ADC ISR, the timer value is
* cleared and starts again from a 0 count. Essentially this example will use
* the Timer_A module to trigger an ADC conversion every 0.5 seconds.
*
* MSP432P401
* ------------------
* /|\| |
* | | |
* --|RST P5.5 |&amp;amp;lt;--- A0 (Analog Input)
* | |
* | |
* | |
* | |
* | |
*
* Author: Timothy Logan
******************************************************************************/
/* DriverLib Includes */
#include "driverlib.h"

/* Standard Includes */
#include <stdint.h>;
#include <stdbool.h>;

#include <printf.h>;

/* Timer_A Continuous Mode Configuration Parameter */
const Timer_A_ContinuousModeConfig continuousModeConfig =
{
TIMER_A_CLOCKSOURCE_ACLK, // ACLK Clock Source
TIMER_A_CLOCKSOURCE_DIVIDER_1, // ACLK/1 = 32Khz
TIMER_A_TAIE_INTERRUPT_DISABLE, // Disable Timer ISR
TIMER_A_DO_CLEAR // Skip Clear Counter
};

/* Timer_A Compare Configuration Parameter */
const Timer_A_CompareModeConfig compareConfig =
{
TIMER_A_CAPTURECOMPARE_REGISTER_1, // Use CCR1
TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE, // Disable CCR interrupt
TIMER_A_OUTPUTMODE_SET_RESET, // Toggle output but
16000 // 16000 Period
};

/* UART Configuration Parameter. These are the configuration parameters to
* make the eUSCI A UART module to operate with a 57600 //9600 baud rate. These
* values were calculated using the online calculator that TI provides
* at:
*http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html
* use eUSCI, 12M clock
*/
// setting the baud rate to 57600 instead of 9600. It will easily support 250 Hz. 9600 should too, PuTTy is just printing slow.

const eUSCI_UART_Config uartConfig =
{
EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
13, //78, // BRDIV = 78
0, //2, // UCxBRF = 2
37, //0, // UCxBRS = 0
EUSCI_A_UART_NO_PARITY, // No Parity
EUSCI_A_UART_LSB_FIRST, // MSB First
EUSCI_A_UART_ONE_STOP_BIT, // One stop bit
EUSCI_A_UART_MODE, // UART mode
EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION // Oversampling
};

/* Statics */
// static volatile uint_fast16_t resultsBuffer[UINT8_MAX];
// static volatile uint8_t resPos;

int main(void)
{
/* Halting WDT */
MAP_WDT_A_holdTimer();
MAP_Interrupt_enableSleepOnIsrExit();
// resPos = 0;

/* Setting up clocks
* MCLK = MCLK = 3MHz
* ACLK = REFO/4 = 32Khz */
MAP_CS_initClockSignal(CS_ACLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);

/* Initializing ADC (MCLK/1/1) */
MAP_ADC14_enableModule();
MAP_ADC14_initModule(ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1,
0);

/* Configuring GPIOs (5.5 A0) */
MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN5,
GPIO_TERTIARY_MODULE_FUNCTION);

/* Configuring ADC Memory */
MAP_ADC14_configureSingleSampleMode(ADC_MEM0, true);
MAP_ADC14_configureConversionMemory(ADC_MEM0, ADC_VREFPOS_AVCC_VREFNEG_VSS,
ADC_INPUT_A0, false);

/* Configuring Timer_A in continuous mode and sourced from ACLK */
MAP_Timer_A_configureContinuousMode(TIMER_A0_MODULE, &continuousModeConfig);

/* Configuring Timer_A0 in CCR1 to trigger at 16000 (0.5s) */
MAP_Timer_A_initCompare(TIMER_A0_MODULE, &compareConfig);

/* Configuring the sample trigger to be sourced from Timer_A0 and setting it
* to automatic iteration after it is triggered*/
MAP_ADC14_setSampleHoldTrigger(ADC_TRIGGER_SOURCE1, false);

/* Enabling the interrupt when a conversion on channel 1 is complete and
* enabling conversions */
MAP_ADC14_enableInterrupt(ADC_INT0);
MAP_ADC14_enableConversion();

/* Enabling Interrupts */
MAP_Interrupt_enableInterrupt(INT_ADC14);
//MAP_Interrupt_enableMaster();

/* Starting the Timer */
MAP_Timer_A_startCounter(TIMER_A0_MODULE, TIMER_A_CONTINUOUS_MODE);

/* Selecting P1.2 and P1.3 in UART mode */
MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);

/* Setting DCO to 12MHz */
CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_12);

/* Configuring UART Module */
MAP_UART_initModule(EUSCI_A0_MODULE, &uartConfig);

/* Enable UART module */
MAP_UART_enableModule(EUSCI_A0_MODULE);

MAP_Interrupt_enableMaster();

/* Going to sleep */
while (1)
{
MAP_PCM_gotoLPM0();
//printf(EUSCI_A0_MODULE, "%u\r\n", resultsBuffer[resPos]); //MAP_ADC14_getResult(ADC_MEM0));
}
}

/* This interrupt is fired whenever a conversion is completed and placed in
* ADC_MEM0 */
void adc_isr(void)
{
uint64_t status;
MAP_Timer_A_clearTimer(TIMER_A0_MODULE);

status = MAP_ADC14_getEnabledInterruptStatus();
MAP_ADC14_clearInterruptFlag(status);

if (status &ADC_INT0)
{
//resultsBuffer[resPos++] = MAP_ADC14_getResult(ADC_MEM0);
printf(EUSCI_A0_MODULE, "%u\r\n", MAP_ADC14_getResult(ADC_MEM0));
}

}

References to try out next:

[ ADCPrintResults_4C123.zip | ~valvano serial ]

[ msp432 ValvanoWare ]

[ prachetverma github ]

[ msp430 ADC -> UART | nischal | reuben ]

Soldering our way from USB Type B to micro USB A | Processing plots for AD8232

We borrowed a USB isolator, but it has a Type B connector, and neither of our boards (MSP432 / Beaglebone) are happy about that (the Uno got burnt out.)

If I had an adapter, we could plug everything together and proceed with testing our new AD8232 kit! But no, we don’t have an adapter, so we soldered one.

Helpful pinouts:

[ source ]

[ source ]

The next step was to sample AD8232’s output using the MSP432. The quickest way forward was to go with CCS cloud and Energia. CCS cloud kept hanging on my computer, so here are Energia links:

[ Energia 16 ] [ xds110 drivers ]

Then I just went with the analog read example (basic.)

The [ hookup guide ] used Processing to plot the sampled data. I couldn’t get their processing sketch to give me a plot (blank screen, map complaining about NaNs.) So, after searching around, I found this alternative that plots lines inside of the draw call:

[ example online ]

I modified this slightly, based on the hook up guide, to only plot a line:

import processing.serial.*;
 
Serial myPort;        // The serial port
int xPos = 1;         // horizontal position of the graph
 
float fValue;
float height_old = 0;

boolean newVal = false;
 
void setup () {
  size(1040, 240);
 
  // println(Serial.list());
  myPort = new Serial(this, Serial.list()[1], 115200);
// change the index [1] to match the serial port being used
  myPort.bufferUntil('\n');
  background(0);
  stroke(127, 34, 255);
}
 
void draw () {
  if (newVal) {
    line(xPos, height_old, xPos, height - fValue);
    if (++xPos >= width) {
      xPos = 0;
      background(0);
    }
    newVal = false;
    height_old = height - fValue;
  }
}
 
void serialEvent (Serial myPort) {
  String inString = myPort.readStringUntil('\n');
  if (inString != null) {
    inString = trim(inString);
    fValue = float(inString);
    fValue = map(fValue, 0, 1023, 0, height);
    newVal = true;
  }
}

Here’s another alternative to try out: [ plotly arduino API ]

The plot I am getting at the moment:bad_output

This is clearly NOT my ECG. I think the AD8232 isn’t messing up, but the sampling on the MSP432 (based on just a delay call), and the plotting itself in Processing 3 need to be optimized.

VNC server on Beaglebone Black

[ NTP time update ]

In the quest to configure wpa2 enterprise through the network manager GUI, I am trying to view the BBB’s desktop. Using an HDMI cable just gave me another login screen. I think I read somewhere that that’s because I didn’t have a keyboard plugged in. That might just apply to a specific OS though…

Anyway, direct HDMI didn’t work, so tried exploring the startx option again. Still couldn’t figure out, and then I came across an alternative: setting up a VNC server. That sounded good, so this followed:

  1. sudo apt-get install x11vnc
  2. sudo apt-get install xvfb
    This was to avoid ‘xvfb could not be found‘:
    xvfb
  3. Got ssvnc on the computer I am using to type this out!
  4. sudo x11vnc -create
    create
  5. This results in a wait loop. That’s when I initiated the connection from ssvnc:
    none

Interestingly, instructions online also include running:

x11vnc bg o %HOME/.x11vnc.log.%VNCDISPLAY auth /var/run/lightdm/root/:0 forever

I am not sure if this is just a one-time setup instruction. I have been able to reset the BBB and establish a link without typing this out (or running a script for it.)

I still didn’t get a GUI in the end. Maybe I am just missing the lxde tools (that’s a big set of packages!)

noGUI

libpruio continued: installing Debian

[ instructions | eMMC flasher direct download ]

[ wpa2 enterprise ]

Image used: BBB-eMMC-flasher-debian-7.8-console-armhf-2015-02-19-2gb

Putting this on the SD card took some time (~10 minutes). I held down boot, powered the BBB with the 5V/1A supply connected to the USB port, and waited for the trickle flash pattern. Surprisingly, it only took a few minutes to get to four solid LEDs!

I first tried directly going to the Cloud9 page but alas, I guess that’s not a part of this image:

gett

This did work on my last debian. I hope I am not messing something up.

Next resort was to go with [ PuTTy ], as I am on a Windows computer.

imageversion

And lolwut

responsibility

This was followed by the usual process for logging into the network, and then apt-get update and apt-get upgrade.

Upgrade failed somewhere. Ran again. Nothing to upgrade…

Proceeding to our new Edimax wi-fi adapter’s drivers!

[ tutorial ] and key steps:

$ lsusb

greprtl

Anyway, this was followed by unsuccessful attempts on getting wifi up and running. My dongle is lit up, but  that’s all. Haven’t been able to get nmcli and /sbin/iw to work just yet.

Next was the most important thing for today, checking if the PRU package shows up:

fml

[ E: can’t locate package ]

Well, in that case. GitHub?

[ element14 assembler ]

But first, I decided to resolve the wi-fi problem using the GUI route. I remembered using startlxde on R-Pi, and it turns out that Debian has startx to do that too. But my image didn’t come by startx, so I had to apt-get it (that is, apt-get xinit)

xinit

The workaround was to remove the lock on the archives.

Solution ]:

If you encounter with the same error, do the following steps.

Run the following command to unlock the apt package managers.

# rm /var/cache/apt/archives/lock

Now update the sources list using command:

# apt-get update

I wonder if there was a good reason for having the lock in the first place. Now apt-get was able to find the PRU package!

pru_package

BAV99 in KiCAD and other AFE4400 / Morpheus Updates

[ KiCAD library format ]

It turns out that KiCAD has a library component for BAV99, but its hard to tell which diode goes to which pin (Unit A or Unit B?) However, the easy fix is to edit one letter in the corresponding library file for enabling pin numbers for this component!

BAV99

With special thanks to TI’s [ eval board ] and the people at [ pulsesensor.com ], here’s the AFE4400 schematic we have so far:

[ Morpheus AFE4400 RevA1 ]

Notes on design choices and things-to-do:

  • Footprints and Mouser part numbers identified for all Rs, Cs, ESD diodes, and the crystal
    • I suggest we go with a somewhat big (easier to solder!) SMD package size for all Rs and Cs: [ 1206 ], as we are not really space constrained at the moment
    • The ESD diodes were slightly trickier to identify, but now we’ll now go with [ BAV99-7-F ]. This has two diodes per package, and that’s what TI has on its eval board.
  • A [ QFN40 footprint | PN532DS ] has been identified for the AFE4400, but its not a 100% match. We might just make a new one.
  • Payne and I have decided to not deal with power management in our first iteration. We’ll just hook up well regulated supplies for now.
  • Photodetetor (PD) still needs to be identified. Our last decision was to go with an Avago chip [ APDS 9008 ], but since AFE4400 already has signal conditioning circuitry built-in for the PD, I am not sure if APDS 9008 will be a good match.
  • Green (530 nm) LEDs still need to be identified. Our original plan of going with some really reverse mount packages by [Kingbright ] might have to be altered, as they haven’t responded to our sample request yet. We might just have to go with options already in stock at Mouser (the one we were looking at is out of stock.)
  • Layout pending until PD, LEDs, footprints are identified. An additional shielding trace will be used to surround the PD traces (see pin VCM in schematic)

LED/PD choices, VQFN footprint for KiCAD, and eval board layout files coming soon!

Codec Setup

1.3vpsu

[ 1.3V supply ]

From [ Audio Cape RevA ]’s BOM:

BeagleBone Audio Cape 8/14/2012
Rev A
ITM QTY PART DESIGNATOR PART DESCRIPTIONS MAN PART # COMMENTS
1 4 C1,C2,C3,C4 10uF,10V CAP CER 10UF 10V Y5V 0805 TDK C2012Y5V1A106Z
3 2 C46,C47 47uF CAP CER 47UF 10V X5R 1210 Murata GRM32ER61A476KE20L
4 4 C48,C49,C53,C61 47pF CAP CER 47PF 50V C0G 5% 0402 TDK C1005C0G1H470J
5 9 C50,C51,C52,C54,C57,C60,C63,C78,C79 0.1uF CAP 0.1uF 16V 10% 0402 X7R Kemet C0402C104K4RACT
6 5 C55,C56,C58,C59,C62 10uF,0805 CAP CER 10UF 10V Y5V 0805 TDK C2012Y5V1A106Z
8 4 D1,D2,D3,D4 PGB0010603MR Ferrite Bead 150 Ohm 800mA Steward LI0805H151R-10
9 2 D5,D6 598-8170-107F LED Green SMD 20mA 2V 0805 Dialight 598-8170-107F
10 3 FB6,FB7,FB8 MMZ1608R301A FERRITE CHIP 300 OHM 500MA 0603 TDK MMZ1608R301A
11 2 P1,P2 2×23 HEADER FEMALE .100 CL Dual Row- Straight Socket Strip- using .025″ Sq. Pins MLE SSHQ-123-D-08-G-LF
2×23 HEADER FEMALE .100 CL Dual Row- Straight Socket Strip- using .025″ Sq. Pins MLE SSHQ-123-D-08-F-LF
12 1 P3 2×5 HEADER FEMALE .100 CL Dual Row- Straight Socket Strip- using .025″ Sq. Pins MLE SSHQ-105-D-08-G-LF
2×5 HEADER FEMALE .100 CL Dual Row- Straight Socket Strip- using .025″ Sq. Pins MLE SSHQ-105-D-08-F-LF
13 2 P6,P7 PHONOJACK STEREO-R CONN JACK STEREO 3POS 3.5MM SMD CUI SJ1-3513-SMT
14 1 Q1 DMC56404 TRANS NPN/NPN W/RES 50V SMINI6 Panasonic DMC564040R
16 3 R108,R109,R110 33,402 RES 33.0 OHM 1/16W 1% 0402 SMD Yaego RC0805FR-0749R9L
17 1 R111 .1,0805 RES .10 OHM 1/8W 5% 0805 CTS 73L3R10J
18 1 R112 28K RES 28.0K OHM 1/16W 1% 0402 SMD Yaego RC0402FR-0728KL
19 1 R113 56.2K RES 56.2K OHM 1/16W 1% 0402 SMD Yaego CRCW040256K2FKED
20 2 R114,R115 5.6K RES 5.6K OHM 1/16W 5% 0402 SMD Yaego RC0402JR-075K6L
21 3 R116,R117,R118 4.75K RES 4.75K OHM 1/16W 1% 0402 SMD  Stackpole Electronics RMCF0402FT4K75
22 2 R119,R120 470,5% RES 470 OHM 1/10W 5% 0402 SMD Panasonic ERJ-2GEJ471X
23 2 R121,R122 100K,1% Resistor 100Kohm 1/16W 1% 0402 Yageo CRCW0402100KJNED
24 1 R123 10K Resistor 10Kohm 1/16W 5% 0402 Rohm MCR01MZPJ103
25 2 R130,R132 402 Resistor Zero ohm Jumper 0402 Yaego RC0402JR-070RL
27 1 SW1 2 POS Dip Switch SWITCH TAPE SEAL 2 POS SMD CTS 219-2MST
29 1 U6 TLV320AIC3106 IC STER AUD CODEC 32 BIT 48-VQFN TI TLV320AIC3106IRGZR
30 1 U7 TPS73701DRBR IC REG LDO CAP FREE 8-SON TI TPS73701DRBR
31 1 U8 CAT24C256W IC EEPROM 256KBIT 400KHZ 8SOIC ON CAT24C256WI-G
33 1 Y1 12MHz OSCILLATOR 12.000 MHZ 3.3V SMD Fox FXO-HC735-12

Using Ti’s FIR, indexing HRIR issues, SW2 is messed up

Replaced UMich’s FIR with the hand-optimized FIR from Ti. Does work better! Exact quantifying needed.

Also found that SW2 on my board is messed up. SW1 works.

Still need to work on indexing filter weights. The current method of copying filter weights inside a for loop just feels wrong. But it works (almost.)

Most of this program is for testing different modes. Only the filtration section at the bottom is really important for this post.

/*
 * fir_filter.c
 * A crude implementation for using HRIRs. A 200 tap HRIR was loaded for each channel.
 *      Author: GSI
 */

#include <usbstk5515.h>
#include <usbstk5515_i2c.h>
#include <AIC_func.h>
#include <sar.h>
#include <stdio.h>
#include <Dsplib.h>
#include "hrir_l_subject3_el10_azAll.h"
#include "hrir_r_subject3_el10_azAll.h"

#define ASIZE 		200

#define TCR0 		*((ioport volatile Uint16 *)0x1810)
#define TIMCNT1_0 	*((ioport volatile Uint16 *)0x1814)
#define TIME_START  0x8001
#define TIME_STOP   0x8000

#define LED_out1 *((ioport volatile Uint16*) 0x1C0A )
#define LED_out2 *((ioport volatile Uint16*) 0x1C0B )
#define LED_dir1 *((ioport volatile Uint16*) 0x1C06 )
#define LED_dir2 *((ioport volatile Uint16*) 0x10C7 )

//initializing LED GPIOs as outputs. LEDs are active low => writing 1s to keep them off
void LED_init() {
	LED_dir1 |= (Uint16) (3 << 14); //GPIOs 14, 15
	LED_dir2 |= (Uint16) 3; 		//GPIOs 16, 17
	//switching them off (driving high)
	LED_out1 |= (Uint16) (3 << 14);
	LED_out2 |= (Uint16) 3;
}

//LED toggling based on index inputted
void toggle_LED(int index) {
	if		(index == 3){ 	//Blue: 					GPIO[14]
		LED_out1 = (Uint16)(3<< (14) );
		LED_out2 = (Uint16)(1<< (0) );
	}
	else if(index == 2) {	//Yellow(ish) <-- LOL: 		GPIO[15]
		LED_out1 = (Uint16)(3<< (14) );
		LED_out2 = (Uint16)(2<< (0) );
	}
	else if(index == 1) {	//Red: 						GPIO[16]
		LED_out1 = (Uint16)(1<< (14) );
		LED_out2 = (Uint16)(3<< (0) );
	}
	else if(index == 0) { 	//Green: 					GPIO[17]
		LED_out1 = (Uint16)(2<< (14) );
		LED_out2 = (Uint16)(3<< (0) );
	}
	else { 	//Green: 					GPIO[17]
		LED_out1 = (Uint16)(3<< (14) );
		LED_out2 = (Uint16)(3<< (0) );
	}
}

Int16 in_left[ASIZE], in_right[ASIZE];
Uint16 delta_time;

Int16 FIR(Int16* in, Int16* hrir,  Uint16 i, Uint16 az)
{
	Int32 sum;
	Uint16 j;
	Uint32 index;
	sum=0;
	//The actual filter work
	for(j=0; j<ASIZE; j++) { if(i>=j)
 			index = i - j;
		else
 			index = ASIZE + i - j;
		sum += (Int32)in[index] * (Int32)hrir[az*ASIZE + j];
	}
	sum = sum + 0x00004000;			// So we round rather than truncate.
	return (Int16) (sum >> 15);  	// Conversion from 32 Q30 to 16 Q15.
}

void main(void)
{
	LED_init();
	Uint16 i, n, az = 0;
//	Uint16 start_time;
//	Uint16 end_time;
	Int16 right[1], left[1]; //AIC inputs
	Int16 out_left[1], out_right[1];
	Int16 dbuffer_l[ASIZE+2] = {0};
	Int16 dbuffer_r[ASIZE+2] = {0};
	Int16 hrir_left[ASIZE], hrir_right[ASIZE];
	Int16 scaling = 16;
	Uint16 key;
	Uint16 filter = 3;

	USBSTK5515_init(); 	//Initializing the Processor
	AIC_init(); 		//Initializing the Audio Codec
	Init_SAR(); 		//Initializing the SAR ADC for key presses
	//Priming the PUMP
	for(i = 0; i < (ASIZE); i++) { AIC_read2(right, left); in_right[i] = right[0]; in_left[i] = left[0]; dbuffer_r[i] = right[0]; dbuffer_l[i] = left[0]; } while(1) { if(i>=ASIZE) i=0;
		//if(j>=WTIME){
		//	if(key == SW2) az += 1;
		//	j = 0;
		//}
		AIC_read2(right, left);
		in_left[i] = left[0];
		in_right[i] = right[0];

		if (filter == 0){ //bypass
			out_left[0] 	= left[0];
			out_right[0] 	= right[0];
		}
		else if (filter == 1){ //redundant calculation (slow down)
			//scaling*FIR(in_left, hrir_l, i, az);
			//scaling*FIR(in_right, hrir_r, i, az);
			out_left[0] 	= left[0]-right[0];
			out_right[0] 	= right[0]-left[0];
		}
		else if (filter == 2){
			fir(in_left,
				hrir_left,
				out_left,
				dbuffer_l,
				1,
				ASIZE);
			fir(in_right,
				hrir_right,
				out_right,
				dbuffer_r,
				1,
				ASIZE);
			out_left[0] 	= left[0];
			out_right[0] 	= right[0];
			//using the HRIR output
			//out_left[0] 	= scaling*FIR(in_left, hrir_l, i, az);
			//out_right[0] 	= scaling*FIR(in_right, hrir_r, i, az);

		}
		else if (filter == 3){
			for (n=0; n<ASIZE; n++){ hrir_left[n] = hrir_l[az*ASIZE +n]; hrir_right[n] = hrir_r[az*ASIZE +n]; } fir(left, hrir_left, out_left, dbuffer_l, 1, ASIZE); fir(right, hrir_right, out_right, dbuffer_r, 1, ASIZE); out_left[0] = scaling*out_left[0]; out_right[0] = scaling*out_right[0]; //mono summed (using left channel) //out_left = scaling*FIR(in_left, hrir_l, i, az); //out_right = scaling*FIR(in_left, hrir_r, i, az); } else{ out_left[0] = 0; out_right[0] = 0; } //POSTFILTER: AIC_write2(out_right[0], out_left[0]); toggle_LED(az%4);//filter); key = Get_Key_Human(); //if (key == SW1) filter += 1; if (key == SW1) az += 1; if (filter>4) filter = 0;
		if (az > 47) az = 0; //az = 48, 49, 50 scaryyy
		i++;

		//printf("%i\n", az);
	}
}