From: Nils Faerber Date: Sun, 5 May 2013 21:22:33 +0000 (+0200) Subject: Make accelerometer work, interrup driven tilt change mode X-Git-Url: https://git.karo-electronics.de/?p=oswald.git;a=commitdiff_plain;h=133faed023f55592a87ee1b8dbc74bc4a8917006 Make accelerometer work, interrup driven tilt change mode --- diff --git a/metawatch/mw_acc.c b/metawatch/mw_acc.c index 270f246..9c4b0f5 100644 --- a/metawatch/mw_acc.c +++ b/metawatch/mw_acc.c @@ -1,12 +1,87 @@ #include #include #include +#include #include "mw_main.h" +#include "mw_uart.h" #include "mw_acc.h" -void mw_init_acc_i2c(void) +#include "oswald_main.h" + +#define ACCEL_STATE_DISABLED 0x00 +#define ACCEL_STATE_ENABLED 0x01 + +static uint8_t AccelState; +static uint8_t AccelerometerBusy; +static uint8_t LengthCount; +static uint8_t Index; +static uint8_t *pAccelerometerData; + +/* + * Accelerometer is a Kionix KXTF9-4100 connected to I2C + * I2C is pretty slow so reading and writing should be done non blocking + * using interrupts. + */ + +#define ACCELEROMETER_NO_INTERRUPTS 0x00 +#define ACCELEROMETER_ALIFG 0x02 +#define ACCELEROMETER_NACKIFG 0x04 +#define ACCELEROMETER_STTIFG 0x06 +#define ACCELEROMETER_STPIFG 0x08 +#define ACCELEROMETER_RXIFG 0x0a +#define ACCELEROMETER_TXIFG 0x0c + +#pragma vector=USCI_B1_VECTOR +__interrupt void ACCERLEROMETER_I2C_ISR(void) +{ + // debug_uart_tx("ACC i2c irq\n"); + switch (USCI_ACCELEROMETER_IV) { + case ACCELEROMETER_NO_INTERRUPTS: + break; + case ACCELEROMETER_ALIFG: + break; + case ACCELEROMETER_NACKIFG: + nop(); + break; + case ACCELEROMETER_STTIFG: + nop(); + break; + case ACCELEROMETER_STPIFG: + break; + case ACCELEROMETER_RXIFG: + if (LengthCount > 0) { + pAccelerometerData[Index++] = ACCELEROMETER_RXBUF; + LengthCount--; + if ( LengthCount == 1 ) { + /* All but one byte received. Send stop */ + ACCELEROMETER_CTL1 |= UCTXSTP; + } else if ( LengthCount == 0 ) { + /* Last byte received; disable rx interrupt */ + ACCELEROMETER_IE &= ~UCRXIE; + AccelerometerBusy = 0; + } + } + break; + case ACCELEROMETER_TXIFG: + if ( LengthCount > 0 ) { + ACCELEROMETER_TXBUF = pAccelerometerData[Index++]; + LengthCount--; + } else { + /* disable transmit interrupt and send stop */ + ACCELEROMETER_IE &= ~UCTXIE; + ACCELEROMETER_CTL1 |= UCTXSTP; + AccelerometerBusy = 0; + } + break; + default: + break; + } + +} + +void mw_acc_init_i2c(void) { /* enable reset before configuration */ ACCELEROMETER_CTL1 |= UCSWRST; @@ -23,49 +98,307 @@ void mw_init_acc_i2c(void) ACCELEROMETER_CTL1 &= ~UCSWRST; } -/* - * DMA2 = SPI for LCD - */ -static void mw_acc_i2c_write_byte(uint8_t byte) +void mw_acc_disable_i2c(void) { - ACCELEROMETER_TXBUF = byte; - while ((ACCELEROMETER_CTL1 & ACCELEROMETER_IFG) == 0) - nop(); + /* enable reset to hold it */ + ACCELEROMETER_CTL1 |= UCSWRST; } -/* OK this is polling write, but data is small and 400kHz I2C, it should "just work" :) */ -void mw_acc_i2c_write(const uint8_t addr, const void *data, const uint8_t len) +void mw_acc_i2c_write(uint8_t RegisterAddress, uint8_t *pData, uint8_t Length) { - int i; - - if (len == 0) { + if (Length == 0 || pData == 0) return; - } while (UCB1STAT & UCBBUSY) nop(); + AccelerometerBusy = 1; + LengthCount = Length; + Index = 0; + pAccelerometerData = pData; + /* + * enable transmit interrupt and * setup for write and send the start condition */ ACCELEROMETER_IFG = 0; ACCELEROMETER_CTL1 |= UCTR + UCTXSTT; - while (!(ACCELEROMETER_IFG & UCTXIFG)) + while(!(ACCELEROMETER_IFG & UCTXIFG)) nop(); /* - * clear transmit interrupt flag, + * clear transmit interrupt flag, enable interrupt, * send the register address */ ACCELEROMETER_IFG = 0; + ACCELEROMETER_IE |= UCTXIE; + ACCELEROMETER_TXBUF = RegisterAddress; - mw_acc_i2c_write_byte(addr); + while (AccelerometerBusy) + nop(); + + while (ACCELEROMETER_CTL1 & UCTXSTP) + nop(); - for (i=0; ix_sc, TRUE); + gtk_widget_set_sensitive(ui_g->y_sc, TRUE); + gtk_widget_set_sensitive(ui_g->z_sc, TRUE); +} + +void hal_accelerometer_disable(void) +{ + g_printerr("accel enable\n"); + gtk_widget_set_sensitive(ui_g->x_sc, FALSE); + gtk_widget_set_sensitive(ui_g->y_sc, FALSE); + gtk_widget_set_sensitive(ui_g->z_sc, FALSE); +} + static gint configure_event (GtkWidget *widget, GdkEventConfigure *event, gpointer user_data) @@ -330,18 +346,24 @@ static void create_mainwin(oswald_ui *ui) sc = gtk_hscale_new_with_range (-128, 127, 1); gtk_box_pack_start (GTK_BOX(hb), sc, TRUE, TRUE, 5); g_signal_connect(G_OBJECT(sc), "value-changed", G_CALLBACK(accelX_value_changed), ui); + ui->x_sc = sc; + gtk_widget_set_sensitive(ui->x_sc, FALSE); l = gtk_label_new("Y:"); gtk_box_pack_start (GTK_BOX(hb), l, FALSE, FALSE, 5); sc = gtk_hscale_new_with_range (-128, 127, 1); gtk_box_pack_start (GTK_BOX(hb), sc, TRUE, TRUE, 5); g_signal_connect(G_OBJECT(sc), "value-changed", G_CALLBACK(accelY_value_changed), ui); + ui->y_sc = sc; + gtk_widget_set_sensitive(ui->y_sc, FALSE); l = gtk_label_new("Z:"); gtk_box_pack_start (GTK_BOX(hb), l, FALSE, FALSE, 5); sc = gtk_hscale_new_with_range (-128, 127, 1); gtk_box_pack_start (GTK_BOX(hb), sc, TRUE, TRUE, 5); g_signal_connect(G_OBJECT(sc), "value-changed", G_CALLBACK(accelZ_value_changed), ui); + ui->z_sc = sc; + gtk_widget_set_sensitive(ui->z_sc, FALSE); gtk_widget_show_all(ui->mainwin); } diff --git a/ui/oswald-ui.h b/ui/oswald-ui.h index 0872a94..fdadd4b 100644 --- a/ui/oswald-ui.h +++ b/ui/oswald-ui.h @@ -9,6 +9,9 @@ typedef struct { GtkWidget *mainwin; GtkWidget *darea; GdkPixmap *pixmap; + GtkWidget *x_sc; + GtkWidget *y_sc; + GtkWidget *z_sc; uint8_t accel_x; uint8_t accel_y; uint8_t accel_z; diff --git a/ui/oswald_hal.h b/ui/oswald_hal.h index ad877d0..bc7a715 100644 --- a/ui/oswald_hal.h +++ b/ui/oswald_hal.h @@ -36,5 +36,9 @@ uint8_t *hal_bluetooth_get_local_bdaddr(void); void hal_bluetooth_set_visible(boolean visible); boolean hal_bluetooth_get_visible(void); void hal_bluetooth_send_data(const void *mdat, uint16_t mlen); + +void hal_accelerometer_enable(void); +void hal_accelerometer_disable(void); + #endif diff --git a/ui/oswald_screens.c b/ui/oswald_screens.c index 9952365..c079e44 100644 --- a/ui/oswald_screens.c +++ b/ui/oswald_screens.c @@ -143,6 +143,8 @@ static accelscreen_data_t accel_screen = { void draw_accel_screen(accel_data_t *accel_data) { + uint8_t x,y; + hal_lcd_clear_display(); oswald_draw_bitmap(36, 0, acc_icon_width, acc_icon_height, acc_icon_bits); @@ -162,7 +164,13 @@ void draw_accel_screen(accel_data_t *accel_data) oswald_draw_line(40, 82, 92, 82); oswald_draw_line(40, 82, 40, 30); - oswald_draw_pixel(41+25+((accel_data->x * 50) / (254)), 31+25+((accel_data->y * 50) / (254))); + x = 41+25+((accel_data->x * 50) / (254)); + y = 31+25+((accel_data->y * 50) / (254)); + oswald_draw_pixel(x, y); + oswald_draw_pixel(x+1, y); + oswald_draw_pixel(x-1, y); + oswald_draw_pixel(x, y+1); + oswald_draw_pixel(x, y-1); hal_lcd_update_display(); } @@ -172,6 +180,11 @@ event_ret_t accel_handle_events(uint16_t event, void *data) switch (event) { case EVENT_SCREEN_VISIBLE: draw_accel_screen(&accel_screen.accdata); + hal_accelerometer_enable(); + return EVENT_RET_HANDLED; + break; + case EVENT_SCREEN_DESTROY: + hal_accelerometer_disable(); return EVENT_RET_HANDLED; break; case EVENT_ACCEL_UPDATE: {