/* Calibration routine for the SCA3000 accelerometer
* using the WaveShare STK128+ Standard development
* board with voltage level jumper set to 3.3 V
* SCA3000 MOSI -> PB2(MOSI)
* SCA3000 MISO -> PB3(MISO)
* SCA3000 SCK -> PB1(SCK)
* SCA3000 CSB -> PB4
* SCA3000 RST -> PB5
* SCA3000 INT (not connected)
* SCA3000 VIN -> 5 V from USB port
* SCA3000 GND -> common ground
* CP2102 USB Converter RX -> PD3 (TXD1)
* Onboard LED -> PB0
*/
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include <string.h>
// _delay_loop_2(18432) = 0.01 s
// Accelerometer readings (x, y, z)
int16_t readings[3];
void SPI_MasterInit(void)
{
uint8_t i;
for(i = 0; i < 100; i++) // 1 sec delay
_delay_loop_2(18432);
// Enable pull-up on PB4(CS0)
PORTB = _BV(PB4);
// Set PB0(LED), PB1(SCK), PB2(MOSI) and PB5(RST0) as output low
// Set PB4(CS0) as output high
DDRB = _BV(DDB0) | _BV(DDB1) | _BV(DDB2) | _BV(DDB4) | _BV(DDB5);
// Enable SPI, Master, set clock rate fck/16
SPCR = _BV(SPE) | _BV(MSTR) | _BV(SPR0); // 460.8 kHz
for(i = 0; i < 100; i++) // 1 sec delay
_delay_loop_2(18432);
// Release SCA3000 reset (PB5)
PORTB |= _BV(PB5);
for(i = 0; i < 25; i++) // 0.25 sec delay
_delay_loop_2(18432);
}
// Read accelerometer x, y and z axis
void readAccelerometer(int16_t* reads)
{
uint8_t azh, azl, ayh, ayl, axh, axl;
// Select SCA3000
PORTB &= ~(_BV(PB4));
SPDR = 0x09 << 2;
while(!(SPSR & _BV(SPIF)));
SPDR = 0x00;
while(!(SPSR & _BV(SPIF)));
azh = SPDR;
SPDR = 0x00;
while(!(SPSR & _BV(SPIF)));
azl = SPDR;
SPDR = 0x00;
while(!(SPSR & _BV(SPIF)));
ayh = SPDR;
SPDR = 0x00;
while(!(SPSR & _BV(SPIF)));
ayl = SPDR;
SPDR = 0x00;
while(!(SPSR & _BV(SPIF)));
axh = SPDR;
SPDR = 0x00;
while(!(SPSR & _BV(SPIF)));
axl = SPDR;
// Deselect SCA3000
PORTB |= _BV(PB4);
reads[2] = ((((int16_t)azh) << 8) + azl) >> 3;
reads[1] = ((((int16_t)ayh) << 8) + ayl) >> 3;
reads[0] = ((((int16_t)axh) << 8) + axl) >> 3;
}
// Take 64 readings and calculate the average
void readAverage(void)
{
int32_t x_accu = 0;
int32_t y_accu = 0;
int32_t z_accu = 0;
for (uint8_t i = 0; i < 64; i++)
{
readAccelerometer(readings);
x_accu += readings[0];
y_accu += readings[1];
z_accu += readings[2];
_delay_loop_2(7089); // 1/260 s delay
}
readings[0] = x_accu / 64;
readings[1] = y_accu / 64;
readings[2] = z_accu / 64;
}
static int uart_putchar1(char c)
{
loop_until_bit_is_set(UCSR1A, UDRE1);
UDR1 = c;
return 0;
}
int main(void)
{
uint8_t i;
char buffer[64];
for(i = 0; i < 100; i++) // 1 second delay
_delay_loop_2(18432);
/* enable serial port UART1 */
/* Set baud rate : 9600 bps @ 7.3728 MHz */
UBRR1L = (unsigned char)(47);
/* Enable transmitter */
UCSR1B = _BV(TXEN1);
SPI_MasterInit();
while(1)
{
PORTB ^= 0x01; // toggle LED
readAverage();
sprintf(buffer, "%5i %5i %5i", readings[0], readings[1], readings[2]);
for(i = 0; i < strlen(buffer); i++)
uart_putchar1((unsigned char)(buffer[i]));
uart_putchar1('\r');
uart_putchar1('\n');
}
}
UPDATE :
I am now using an improved procedure for accelerometer calibration, which adds a correction for axis misalignments (cross-talk).
See:
See: