MPU-9250 sample rate lower than the one selected in register map - i2c

I'm using Arduino UNO and I2C protocol to read data from MPU 9250 in arduino IDE. But the sampling rate is lower than the one I selected, indeed, I try to use 1KHz but the maximum speed I can reach is by reading only one of the sensors and is 25 Hz. Do you know I can improve the speed of sampling?
This is my code:
float ax, ay, az, gx, gy, gz;//Some original data of accelerometer, gyroscope and magenetometer
float mx, my, mz;
float magCalibration[3]={0, 0 ,0};
int16_t accelCount[3]; // Stores the 16-bit signed accelerometer sensor output
int16_t gyroCount[3]; // Stores the 16-bit signed gyro sensor output
int16_t magCount[3]; // Stores the 16-bit signed magnetometer sensor output
// Specify sensor full scale
uint8_t Gscale = 0; //GFS_250DPS;
uint8_t Ascale = 0; //AFS_2G;
uint8_t Mscale = 1; // Choose either 14-bit or 16-bit magnetometer resolution
uint8_t Mmode = 0x02; // 2 for 8 Hz, 6 for 100 Hz continuous magnetometer data read
// scale resolutions per LSB for the sensors
float gRes = 250./32768.0; // *(PI/180.0); degrees/s
float mRes = 1000.*4219./32760.0; // nT
float aRes = 2./32768.0; //g
float lastUpdate=0;
float Now, deltat;
void setup() {
Wire.begin();//Initialize
Serial.begin(115200);//Initialize the serial
//MyBlue.begin(9600);
initMPU9250(); //Inititalize the accelerometer
initAK8963(magCalibration);//Initialize the magnetometer
//int tickEvent1=t.every(timeChange, get_motion);
//int tickEvent2=t.every(500, printout) ;//print out the serial 50 after this line
}
void loop() {
get_motion();
printout();
Now = micros();
deltat = ((Now - lastUpdate)/1000000.0f); // set integration time by time elapsed since last filter update
lastUpdate = Now;
Serial.println(deltat);
}
void printout()
{
Serial.print(ax);
Serial.print(',');
Serial.print(ay);
Serial.print(',');
Serial.println(az);
Serial.print(',');
Serial.print(gx);
Serial.print(',');
Serial.print(gy);
Serial.print(',');
Serial.println(gz);
Serial.print(',');
Serial.print(mx);
Serial.print(',');
Serial.print(my);
Serial.print(',');
Serial.println(mz);
}
void get_motion()
{
if (readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01) { // On interrupt, check if data ready interrupt
readAccelData(accelCount); // Read the x/y/z adc values
// Now we'll calculate the accleration value into actual g's
ax = (float)accelCount[0] * aRes;// * 9.81;
ay = (float)accelCount[1] * aRes; //* 9.81;
az = (float)accelCount[2] * aRes; //* 9.81;
readGyroData(gyroCount); // Read the x/y/z adc values
// Calculate the gyro value into actual degrees per second
gx = (float)gyroCount[0] * gRes;
gy = (float)gyroCount[1] * gRes;
gz = (float)gyroCount[2] * gRes;
readMagData(magCount); // Read the x/y/z adc values
// Calculate the magnetometer values in milliGauss
// Include factory calibration per data sheet and user environmental corrections
mx = (float)magCount[0] * mRes * magCalibration[0];
my = (float)magCount[1] * mRes * magCalibration[1];
mz = (float)magCount[2] * mRes * magCalibration[2];
}
}
void readAccelData(int16_t * destination)
{
uint8_t rawData[6]; // x/y/z accel register data stored here
readBytes(MPU9250_ADDRESS, ACCEL_XOUT_H, 6, &rawData[0]); // Read the six raw data registers into data array
destination[0] = ((int16_t)rawData[0] << 8) | rawData[1] ; // Turn the MSB and LSB into a signed 16-bit value
destination[1] = ((int16_t)rawData[2] << 8) | rawData[3] ;
destination[2] = ((int16_t)rawData[4] << 8) | rawData[5] ;
}
void readGyroData(int16_t * destination)
{
uint8_t rawData[6]; // x/y/z gyro register data stored here
readBytes(MPU9250_ADDRESS, GYRO_XOUT_H, 6, &rawData[0]); // Read the six raw data registers sequentially into data array
destination[0] = ((int16_t)rawData[0] << 8) | rawData[1] ; // Turn the MSB and LSB into a signed 16-bit value
destination[1] = ((int16_t)rawData[2] << 8) | rawData[3] ;
destination[2] = ((int16_t)rawData[4] << 8) | rawData[5] ;
}
void readMagData(int16_t * destination)
{
uint8_t rawData[7]; // x/y/z gyro register data, ST2 register stored here, must read ST2 at end of data acquisition
//read mag
writeByte(MPU9250_ADDRESS, INT_PIN_CFG, 0x02); //set i2c bypass enable pin to true to access magnetometer
delay(10);
writeByte(AK8963_ADDRESS, 0x0A, 0x01); //enable the magnetometer
delay(100);
if(readByte(AK8963_ADDRESS, AK8963_ST1) & 0x01) { // wait for magnetometer data ready bit to be set
readBytes(AK8963_ADDRESS, AK8963_XOUT_L, 6, &rawData[0]); // Read the six raw data and ST2 registers sequentially into data array
uint8_t c = rawData[6]; // End data read by reading ST2 register
//if(!(c & 0x08)) { // Check if magnetic sensor overflow set, if not then report data
destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ; // Turn the MSB and LSB into a signed 16-bit value
destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ; // Data stored as little Endian
destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
//}
}
}
void initAK8963(float * destination)
{
// First extract the factory calibration for each magnetometer axis
uint8_t rawData[3]; // x/y/z gyro calibration data stored here
writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer
delay(10);
writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x0F); // Enter Fuse ROM access mode
delay(10);
readBytes(AK8963_ADDRESS, AK8963_ASAX, 3, &rawData[0]); // Read the x-, y-, and z-axis calibration values
destination[0] = (float)(rawData[0] - 128)/256. + 1.; // Return x-axis sensitivity adjustment values, etc.
destination[1] = (float)(rawData[1] - 128)/256. + 1.;
destination[2] = (float)(rawData[2] - 128)/256. + 1.;
writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer
delay(10);
// Configure the magnetometer for continuous read and highest resolution
// set Mscale bit 4 to 1 (0) to enable 16 (14) bit resolution in CNTL register,
// and enable continuous mode data acquisition Mmode (bits [3:0]), 0010 for 8 Hz and 0110 for 100 Hz sample rates
writeByte(AK8963_ADDRESS, AK8963_CNTL, Mscale << 4 | Mmode); // Set magnetometer data resolution and sample ODR
delay(10);
}
void initMPU9250()
{
// wake up device
//writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x80);
delay(100);
writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x00); // Clear sleep mode bit (6), enable all sensors
delay(100); // Wait for all registers to reset
// get stable time source
writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x01); // Auto select clock source to be PLL gyroscope reference if ready else
delay(200);
// Configure Gyro and Thermometer
// Disable FSYNC and set thermometer and gyro bandwidth to 41 and 42 Hz, respectively;
// minimum delay time for this setting is 5.9 ms, which means sensor fusion update rates cannot
// be higher than 1 / 0.0059 = 170 Hz
// DLPF_CFG = bits 2:0 = 011; this limits the sample rate to 1000 Hz for both
// With the MPU9250, it is possible to get gyro sample rates of 32 kHz (!), 8 kHz, or 1 kHz
writeByte(MPU9250_ADDRESS, CONFIG, 0x01);
// Set sample rate = gyroscope output rate/(1 + SMPLRT_DIV)
writeByte(MPU9250_ADDRESS, SMPLRT_DIV, 0x00); // Use a 200 Hz rate; a rate consistent with the filter update rate
// determined inset in CONFIG above
// Set gyroscope full scale range
// Range selects FS_SEL and GFS_SEL are 0 - 3, so 2-bit values are left-shifted into positions 4:3
uint8_t c = readByte(MPU9250_ADDRESS, GYRO_CONFIG); // get current GYRO_CONFIG register value
// c = c & ~0xE0; // Clear self-test bits [7:5]
c = c & ~0x03; // Clear Fchoice bits [1:0]
c = c & ~0x18; // Clear GFS bits [4:3]
c = c | Gscale << 3; // Set full scale range for the gyro
// c =| 0x00; // Set Fchoice for the gyro to 11 by writing its inverse to bits 1:0 of GYRO_CONFIG
writeByte(MPU9250_ADDRESS, GYRO_CONFIG, c ); // Write new GYRO_CONFIG value to register
// Set accelerometer full-scale range configuration
c = readByte(MPU9250_ADDRESS, ACCEL_CONFIG); // get current ACCEL_CONFIG register value
// c = c & ~0xE0; // Clear self-test bits [7:5]
c = c & ~0x18; // Clear AFS bits [4:3]
c = c | Ascale << 3; // Set full scale range for the accelerometer
writeByte(MPU9250_ADDRESS, ACCEL_CONFIG, c); // Write new ACCEL_CONFIG register value
// Set accelerometer sample rate configuration
// It is possible to get a 4 kHz sample rate from the accelerometer by choosing 1 for
// accel_fchoice_b bit [3]; in this case the bandwidth is 1.13 kHz
c = readByte(MPU9250_ADDRESS, ACCEL_CONFIG2); // get current ACCEL_CONFIG2 register value
c = c & ~0x0F; // Clear accel_fchoice_b (bit 3) and A_DLPFG (bits [2:0])
c = c | 0x02; // Set accelerometer rate to 1 kHz and bandwidth to 41 Hz
writeByte(MPU9250_ADDRESS, ACCEL_CONFIG2, c); // Write new ACCEL_CONFIG2 register value
// The accelerometer, gyro, and thermometer are set to 1 kHz sample rates,
// but all these rates are further reduced by a factor of 5 to 200 Hz because of the SMPLRT_DIV setting
// Configure Interrupts and Bypass Enable
// Set interrupt pin active high, push-pull, hold interrupt pin level HIGH until interrupt cleared,
// clear on read of INT_STATUS, and enable I2C_BYPASS_EN so additional chips
// can join the I2C bus and all can be controlled by the Arduino as master
writeByte(MPU9250_ADDRESS, INT_PIN_CFG, 0x22);
writeByte(MPU9250_ADDRESS, INT_ENABLE, 0x01); // Enable data ready (bit 0) interrupt
delay(100);
}
// Wire.h read and write protocols
void writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
{
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.write(data); // Put data in Tx buffer
Wire.endTransmission(); // Send the Tx buffer
}
uint8_t readByte(uint8_t address, uint8_t subAddress)
{
uint8_t data; // `data` will store the register data
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
Wire.requestFrom(address, (uint8_t) 1); // Read one byte from slave register address
data = Wire.read(); // Fill Rx buffer with result
return data; // Return data read from slave register
}
void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest)
{
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
uint8_t i = 0;
Wire.requestFrom(address, count); // Read bytes from slave register address
while (Wire.available()) {
dest[i++] = Wire.read(); } // Put read results in the Rx buffer
}

With the settings you have in initMPU9250, I don't see any reason not to get 1kHz sampling rate. However, Serial.print may be slowing you down. I suggest reducing the rate of your Serial dumps to 0.5s intervals to see if the situation improves.
EDIT:
I just noticed a few things that are wrong in your readMagData function.
Move these statements to the appropriate place in initAK8963:
//read mag
writeByte(MPU9250_ADDRESS, INT_PIN_CFG, 0x02); //set i2c bypass enable pin to true to access magnetometer
delay(10);
writeByte(AK8963_ADDRESS, 0x0A, 0x01); //enable the magnetometer
delay(100);
because performing those actions on every data read will slow you down to below 10 Hz. They are configuration commands that are meant to be done once upon init of the sensor.
Reading the AK8963 data requires actually reading an extra register in order for the read to trigger. Change the 6 to a 7 in this line like so:
readBytes(AK8963_ADDRESS, AK8963_XOUT_L, 7, &rawData[0]);

Related

Frequency Adjusting with STM32 DAC

I used STM32F407VG to create a 30 khz sine wave. Timer settings are; Prescaler = 2-1, ARR = 1, also the clock is 84 Mhz(the clock which runs DAC).
I wrote a function called generate_sin();
#define SINE_ARY_SIZE (360)
const int MAX_SINE_DEGERI = 4095; // max_sine_value
const double BASLANGIC_NOKTASI = 2047.5; //starting point
uint32_t sine_ary[SINE_ARY_SIZE];
void generate_sine(){
for (int i = 0; i < SINE_ARY_SIZE; i++){
double deger = (sin(i*M_PI*360/180/SINE_ARY_SIZE) * BASLANGIC_NOKTASI) + BASLANGIC_NOKTASI; //double value
sine_ary[i] = (uint32_t)deger; // value
}
This is the function which creates sine wave. I used HAL DMA to send DAC output variables.
HAL_TIM_Base_Start(&htim2);
generate_sine();
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, sine_ary, SINE_ARY_SIZE, DAC_ALIGN_12B_R);
These are the codes i used to do what i want. But im having a trouble to change frequency without changing prescaler or ARR.
So here is my question. Can i change frequency without changing timer settings ? For example i want to use buttons and whenever i push button i want my frequency to change.
The generate_sine function will give you one period of a sine wave which has SINE_ARY_SIZE of samples.
To increase the frequency you need to make the period shorter (for 2x frequency, you would have half the number of samples per period). So you should calculate the array for smaller SINE_ARY_SIZE (which will fill just part of the original buffer with a shorter sine wave) and also put this smaller value in the HAL_DAC_Start_DMA function.
Decreasing the frequency will require making the array longer.
You should declare the sine_ary with a maximum length that you will need (for lowest frequency). Make sure it fits in RAM.
#define MAXIMUM_ARRAY_LENGTH 360
uint32_t usedArrayLength = 180;
const double amplitude = 2047.5;
uint32_t sine_ary[MAXIMUM_ARRAY_LENGTH];
void generate_sine(){
for (int i = 0; i < usedArrayLength; i++){
double value = (sin(i*M_PI*2/usedArrayLength) * amplitude) + amplitude;
sine_ary[i] = (uint32_t)value; // value
}
This will have two times higher frequency than the original code, because it only has 180 samples per period, compared to 360.
Start it using
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, sine_ary, usedArrayLength, DAC_ALIGN_12B_R);
To change the frequency, stop DAC, change the value of usedArrayLength (smaller value means higher frequency, must be less or equal to MAXIMUM_ARRAY_LENGTH). Then call the generate_sine function and start the DAC again by the same function (that now uses new usedArrayLength).
Frequency will be: Clock/prescaler/ARR/usedArrayLength
Also, you should use uint16_t for the array (values are from 0 to 4095, the DAC is 12bit I suppose) and DMA should be set to Half-word (2 bytes per value).

How to calibrate internal temperature sensor value in STM32 L496ZGT4

I'm creating simple project using STM32 L946ZGT4. I'd like to use the internal temperature sensor. I configured ADC and i can get value from this. My problem is with calibrate this sensor. Using Reference Manual and Datasheet instructions my final value in celsius degrees equals -17. The ADC value is about 800. Here is my code for sensor calibrating.
#include "Myfun.h"
#include "HD44780.h"
extern uint16_t tab[100];
char buf[16];
float sum, avg;
#define TS_CAL1((uint16_t*)((uint32_t) 0x1FFF75A8))
#define TS_CAL2((uint16_t*)((uint32_t) 0x1FFF75CA))
#define TS_CAL1_TEMP 30.0 f
#define TS_CAL2_TEMP 130.0 f
int32_t temperature;
int main(void)
{
SysTick_Config(4000000 / 1000);
LCD_Init();
Led_Conf();
ADC_Conf_DMA_TempSensor();
while (1)
{
sum = 0;
for (int i = 0; i < 100;)
{
sum = sum + tab[i];
++i;
}
avg = sum / 100; // here is my value from ADC
temperature = (int32_t)(((TS_CAL2_TEMP - TS_CAL1_TEMP) / ((float)(*TS_CAL2) - (float)(*TS_CAL1))) *
(avg - (float)(*TS_CAL1)) + 30.0);
sprintf(buf, "%d C", temperature);
LCD_Clear();
LCD_WriteText(buf);
delay_ms(60);
}
}
you have to convert your ADC reading to volt by:
ADC_value / ADC_maxvalue * ADC_refvoltage
with
ADC_value: the value you get back from the ADC
ADC_maxvalue: 2^12 = 4096, when you are sampling in the 12-bit mode
ADC_revoltage: 3.3 Volt, typically - except you are using a different reference voltage
Then apply the formula from the datasheet, chapter "Electrical Characteristics" --> "Operating Conditions" --> "Temperature Sensor", where you find the offset and the scale (plus the formula) to convert the voltage to temperature ...

STM32 HSE unstable frequency

I'm trying to run my Nucleo f401re on 80mhz from HSE
int F4xxx::clockInit(int pllM, int pllN, int pllP, int pllQ)
{
enableHse();
//FLASH
CLEAR_BIT(FLASH->ACR, FLASH_ACR_PRFTEN);
FLASH->ACR&= ~FLASH_ACR_LATENCY;
FLASH->ACR |= FLASH_ACR_LATENCY_5WS | FLASH_ACR_ICEN | FLASH_ACR_DCEN|FLASH_ACR_PRFTEN;
//set HSE as PLL source
RCC->PLLCFGR = RCC_PLLCFGR_PLLSRC_HSE;
//
RCC->CR &= ~(RCC_CR_PLLON); //disable PLL before changes
//
RCC->PLLCFGR = pllM|(pllN<<6)|(((pllP>>1)-1)<<16)|RCC_PLLCFGR_PLLSRC_HSE|(pllQ<<24);
RCC->CR|=RCC_CR_PLLON;
while(!(RCC->CR&RCC_CR_PLLRDY));
RCC->CFGR &= ~(RCC_CFGR_HPRE); //Prescaler 1
RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB = SYSCLK/1
//APB2 Prescaler 2
RCC->CFGR &= ~(RCC_CFGR_PPRE2);
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1; //APB2 /1
RCC->CFGR &= ~(RCC_CFGR_PPRE1);
RCC->CFGR|=RCC_CFGR_PPRE1_DIV1; // APB1 /2
RCC->CFGR &= ~RCC_CFGR_SW; // reset SW0, SW1.
RCC->CFGR |= RCC_CFGR_SW_PLL;
RCC->CR|=RCC_CR_PLLON;
while((RCC->CFGR & RCC_CFGR_SWS)!=RCC_CFGR_SWS_PLL); // wait for switching to PLL (while PLL is not used as system clock)
// for power saving
RCC->CR &= ~(RCC_CR_HSION);
return 0;
}
void F4xxx::enableHse()
{
// for control MCO2 (PC9): (freq=SYSCLK/5)
RCC->AHB1ENR|=RCC_AHB1ENR_GPIOCEN;
GPIOC->MODER&=~GPIO_MODER_MODE9;
GPIOC->MODER|=GPIO_MODER_MODE9_1;
GPIOC->OSPEEDR|=GPIO_OSPEEDER_OSPEEDR9;
RCC->CFGR|=RCC_CFGR_MCO2PRE;
RCC->CR |= (RCC_CR_HSEON); //Enable HSE
while( !(RCC->CR & RCC_CR_HSERDY) ) {}; //ready to start HSE
}
and then call it like this:
f4.clockInit(8, 336, 2, 7);
But my logic analyzer show that the frequency is unstable
The peaks with level=1 have width^-1 = 16 mhz
But the peaks with level=0 have width^-1 = 8 mhz and 5.33 mhz
What could cause such an unstable frequency?
If I'm not mistaken, your logic analyzer screenshot is from the Saleae software. Unless you have one of the latest models which uses USB 3, I guess your sampling frequency is limited to 24 MHz max. This is also the case for FX2 based cheap clones. Basically, you need USB 3 OR Internal Buffer Memory OR ability to sample reduced number of channels, like 3 or so in order to sample faster than 24 MHz.
You didn't tell your sampling frequency, but based on the available info, I assume that it's limited to 24 MHz. Nyquist Sampling Theorem states that you need to sample at least 2 times faster than the signal you measure. So, for a 16 MHz signal you need at least 32 MHz sampling rate. At lower sampling frequencies, you observe a phenomena called aliasing, where the signal you measure seems to have a lower frequency.
Keep it in mind that 32 MHz is the theoretical minimum and you still may (and probably will) observe distortions in the signal. For analog signals, x10 or x20 sampling rates are generally used. For digital signal like you measure, x4 is probably fine.
Not long ago, I had to debug USB Full Speed bus (12 MHz) with a Saleae clone. Using 24 MHz sampling rate sometimes worked and sometimes didn't. When it didn't, I hit the button and tried my chance again...
So, you probably don't have an issue at all. You are just unable to measure your signal correctly because of the limitation of your equipment. When you repeat your measurements, you will probably have the same sampling issues from time to time.

Transmitting data from Arduino UNO into MATLAB but getting a lot of NaNs and numbers with missing digits

I'm collecting degree data from an encoder using an Arduino Uno, and then sending that data into MATLAB using USB. In order to get velocity of rotation as well, I'm generating and sending a timestamp after every degree data point from the Arduino into MATLAB. The data is generated flawlessly on the Arduino side--there's nothing wrong on the Serial Monitor.
In MATLAB, however, my data matrices fill up with quite a few NaNs, as well as the occasional integer with a missing first digit. For example, instead of 216 degree, I get 16 degrees coming through, or instead of 7265900 microseconds, I get 265900 microseconds coming through.
I've been able to solve the issue of losing time data by using Arduino's millis() clock instead of its micros() clock and by adding a 50 millisecond delay after the encoder reading. The problem of degree data loss goes away if I increase the delay after the millis() clock, but then degree data acquisition becomes too slow to be useful.
Any help would be much appreciated!
Code pasted below. First the Arduino code, then the MATLAB code.
Thank you!
David
#include <Adafruit_LEDBackpack.h>
#include <Adafruit_GFX.h>
#include <gfxfont.h>
#include <SPI.h> //Include the SPI library in this sketch.
#include <Wire.h> // Enable this line if using Arduino Uno, Mega, etc.
//#include <TinyWireM.h> // Enable this line if using Adafruit Trinket, Gemma, etc.
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
Adafruit_7segment matrix = Adafruit_7segment();
//Variables for SPI rotary encoder
boolean knob_detected = false;
byte slave_select = 10; //Slave select pin.
byte mosi = 11; //MOSI pin.
byte miso = 12; //MISO pin.
byte spi_clock = 13; //Clock pin.
byte read_counter = 96;
byte write_mode0 = 137;
byte write_mode1 = 144;
byte count1;
byte count2;
int count;
int val;
int button = 7;
int b = 0;
int degree;
int absolute;
unsigned long time;
// SETUP //
void setup() {
//Connect the 4 communication pins between the Arduino and the quadrature counter.
#ifndef __AVR_ATtiny85__
Serial.begin(9600);
//Serial.println("7 Segment Backpack Test");
#endif
matrix.begin(0x70);
pinMode(slave_select, OUTPUT);
pinMode(mosi, OUTPUT);
pinMode(miso, INPUT);
pinMode(spi_clock, OUTPUT);
// pinMode(button,INPUT);
SPI.begin(); //Begin SPI communication.
SPI.setBitOrder(MSBFIRST); //Bytes read into SPI will be read in MSB style.
SPI.setDataMode(SPI_MODE0); //Set the data to shift on the low clock phase with normal (non-inverted) clock polarity.
digitalWrite(slave_select, HIGH); //Close the SPI communication port.
SPI.setClockDivider(SPI_CLOCK_DIV128); //Set the SPI clock to 125 kHz (This can be changed).
digitalWrite(slave_select, LOW); //Set slave select low to enable communication.
SPI.transfer(write_mode0); //Select mode 0 for modifying.
SPI.transfer(0b01000011); //Write to mode 0: Synchronous Index, disable index, range-limit count mode, x4 quadrature.
digitalWrite(slave_select, HIGH); //Set slave select high to disable communication
digitalWrite(slave_select, LOW); //Set slave select low to enable communication
SPI.transfer(write_mode1); //Select mode 1 for modifying.
SPI.transfer(2); //Write across a 0b01 to mode1 to enable 2 byte data transfers
digitalWrite(slave_select, HIGH); //Set slave select high to disable communication
Serial.begin(9600); //Set the baud rate for serial data transmission.
//Serial.println("READY"); //Print "READY" to the serial line to indicate that initialization is complete.
}
// MAIN LOOP //
void loop() {
digitalWrite(slave_select, LOW); //Set slave_select pin low to begin tranmission .
SPI.transfer(read_counter); //Read from the read_counter register.
count1 = SPI.transfer(0); //Send a null transfer to read byte1 values.
count2 = SPI.transfer(0); //Send a null transfer to read byte2 values.
digitalWrite(slave_select, HIGH); //Set slave_select high to end transmission.
count = word(count1, count2); //Type cast the 2 bytes as a word.
degree = count / 4;
absolute = abs(degree);
//Send back the value of the register over the serial line.
b = digitalRead(button);
if (b == HIGH) {
digitalWrite(absolute,LOW);
}
else {}
if (absolute == LOW)
{
absolute = 0;
}
else {}
Serial.println(absolute); //Send back the value of the register over the serial line.
matrix.print(absolute,DEC);
matrix.writeDisplay();
delay(50); //Pause for 50 milliseconds before re-looping.
time = millis();
Serial.println(time);
delay(10);
}
clear all;
close all;
clc;
delete(instrfind); %delete connected ports
p=getserialport;
[m,n] = listdlg('PromptString','Select Your Bluetooth device:','SelectionMode','single','ListString',p);
com=cell2mat(p(m));
s=serial(com);
fopen(s);
csd = figure;
set(csd,'Name','Plotting Arduino Data on MATLAB','NumberTitle','off'); % open Figure
t=1:100;% total Figure
hAx(1) = subplot(211);
hLine(1) = line('XData',t, 'YData',nan(size(t)), 'Color','b', 'Parent',hAx(1));
xlabel('Samples'), ylabel('Degrees');
hAx(2) = subplot(212);
hLine(2) = line('XData',t, 'YData',nan(size(t)), 'Color','b', 'Parent',hAx(2));
xlabel('Samples'), ylabel('Velocity');
set(hAx, 'Box','on', 'YGrid','on');
axis(hAx(1),[0,100,0,100]);
axis(hAx(2),[0,100,0,100000]);
d=zeros(1,100); %buffer of 100 elements
sm=zeros(1,10); %buffer of 10 elements
t10=zeros(1,10); %buffer of 10 elements
t100=zeros(1,100); %buffer of 100 elements
while(1)
j=1;
while(j<=10)
flushinput(s);
sc=(fscanf(s));
if(length(sc)<6) %1000 degree units = 6 char (was <7 for micros() clock)
sm(j)=str2double(sc);
else %i.e. else, if a timestamp (more than 7 chars)
t10(j)=str2double(sc);
j=j+1;
end
end
t100 = [t100,t10];
t100 = t100(11:end);
d=[d,sm]; %Add new Samples
d=d(11:end); %Remove old Samples
%d(end)
set(hLine(1), 'YData',d); %draw Degrees
set(hLine(2), 'YData',t100); %draw Velocity (currently just timestamps)
drawnow %# force MATLAB to flush any queued displays
end
(getserialport function defined by the following m-file)
function x=getserialport
serialInfo = instrhwinfo('serial');
x=serialInfo.SerialPorts;
end

Help with IIR Comb Filter

Reverb.m
#define D 1000
OSStatus MusicPlayerCallback(
void* inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames
AudioBufferList * ioData){
MusicPlaybackState *musicPlaybackState = (MusicPlaybackState*) inRefCon;
//Sample Rate 44.1
float a0,a1;
double y0, sampleinp;
//Delay Gain
a0 = 1;
a1 = 0.5;
for (int i = 0; i< ioData->mNumberBuffers; i++){
AudioBuffer buffer = ioData->mBuffers[i];
SIn16 *outSampleBuffer = buffer.mData;
for (int j = 0; j < inNumberFrames*2; j++) {
//Delay Left Channel
sampleinp = *musicPlaybackState->samplePtr++;
/* IIR equation of Comb Filter
y[n] = (a*x[n])+ (b*x[n-D])
*/
y0 = (a0*sampleinp) + (a1*sampleinp-D);
outSample[j] = fmax(fmin(y0, 32767.0), -32768.0);
j++;
//Delay Right Channel
sampleinp = *musicPlaybackState->samplePtr++;
y0 = (a0*sampleinp) + (a1*sampleinp-D);
outSample[j] = fmax(fmin(y0, 32767.0), -32768.0);
}
}
}
Ok, I got a lot of info but I'm having trouble implementing it. Can someone help, it's probably something really easy i'm forgeting. It's just playing back as normal with a little boost but no delays.
Your treatment of the x0[] variables doesn't look right -- the way you have it, the left and right channels will be intermingled. You assign to x0[j] for the left channel, then
overwrite x0[j] with the right channel data. So the delayed signal x0[j-D] will
always correspond to the right channel, with the delayed left channel data being lost.
You didn't say what your sample rate is, but for a typical audio application, a
three-sample delay might not have much of an audible effect. At 44.1 ksamp/sec,
with a 3-sample delay the peaks and troughs of the filter response will be at
multiples of 14,700 Hz. All you'll get is a single peak in the audio frequency
range, in a part of the spectrum where there's hardly any power (assuming the
signal is speech or music).