From 6f08f8ce51adf06aa64743faa713c6b7a7c2db9a Mon Sep 17 00:00:00 2001 From: Damien Date: Wed, 23 Oct 2013 22:17:26 +0100 Subject: [PATCH] Add working MMA support. --- py/runtime.c | 4 ++ py/runtime.h | 1 + stm/main.c | 129 ++++++++++++++++++++++++++++++--------------------- stm/mma.c | 62 +++++++++++++++++++++++-- 4 files changed, 137 insertions(+), 59 deletions(-) diff --git a/py/runtime.c b/py/runtime.c index 9da568876..a1bd67636 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -319,6 +319,10 @@ static bool fit_small_int(py_small_int_t o) { return true; } +py_obj_t py_obj_new_int(int value) { + return TO_SMALL_INT(value); +} + py_obj_t py_obj_new_const(const char *id) { py_obj_base_t *o = m_new(py_obj_base_t, 1); o->kind = O_CONST; diff --git a/py/runtime.h b/py/runtime.h index 326ca0833..98d77c8e7 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -99,6 +99,7 @@ void py_obj_print(py_obj_t o); int rt_is_true(py_obj_t arg); int py_get_int(py_obj_t arg); qstr py_get_qstr(py_obj_t arg); +py_obj_t py_obj_new_int(int value); py_obj_t rt_load_const_str(qstr qstr); py_obj_t rt_load_name(qstr qstr); py_obj_t rt_load_global(qstr qstr); diff --git a/stm/main.c b/stm/main.c index 94c40f27e..801a0decd 100644 --- a/stm/main.c +++ b/stm/main.c @@ -433,6 +433,24 @@ py_obj_t pyb_servo_set(py_obj_t value) { return py_const_none; } +#define MMA_ADDR (0x4c) + +py_obj_t pyb_mma_read() { + mma_start(MMA_ADDR, 1); + mma_send_byte(0); + mma_restart(MMA_ADDR, 0); + py_obj_t data[4]; + for (int i = 3; i >= 1; i--) { + int v = mma_read_ack() & 0x3f; + if (v & 0x20) { + v |= ~0x1f; + } + data[i] = py_obj_new_int(v); + } + data[0] = py_obj_new_int(mma_read_nack()); + return rt_build_tuple(4, data); // items in reverse order in data +} + int main(void) { // TODO disable JTAG @@ -480,6 +498,7 @@ soft_reset: rt_store_attr(m, qstr_from_str_static("led"), rt_make_function_1(pyb_led)); rt_store_attr(m, qstr_from_str_static("sw"), rt_make_function_0(pyb_sw)); rt_store_attr(m, qstr_from_str_static("servo"), rt_make_function_1(pyb_servo_set)); + rt_store_attr(m, qstr_from_str_static("mma"), rt_make_function_0(pyb_mma_read)); rt_store_name(qstr_from_str_static("pyb"), m); } @@ -554,6 +573,62 @@ soft_reset: // USB usb_init(); + // MMA + { + // init and reset address to zero + mma_init(); + mma_start(MMA_ADDR, 1); + mma_send_byte(0); + mma_stop(); + + /* + // read and print all 11 registers + mma_start(MMA_ADDR, 1); + mma_send_byte(0); + mma_restart(MMA_ADDR, 0); + for (int i = 0; i <= 0xa; i++) { + int data; + if (i == 0xa) { + data = mma_read_nack(); + } else { + data = mma_read_ack(); + } + printf(" %02x", data); + } + printf("\n"); + */ + + // put into active mode + mma_start(MMA_ADDR, 1); + mma_send_byte(7); // mode + mma_send_byte(1); // active mode + mma_stop(); + + /* + // infinite loop to read values + for (;;) { + sys_tick_delay_ms(500); + + mma_start(MMA_ADDR, 1); + mma_send_byte(0); + mma_restart(MMA_ADDR, 0); + for (int i = 0; i <= 3; i++) { + int data; + if (i == 3) { + data = mma_read_nack(); + printf(" %02x\n", data); + } else { + data = mma_read_ack() & 0x3f; + if (data & 0x20) { + data |= ~0x1f; + } + printf(" % 2d", data); + } + } + } + */ + } + // turn boot-up LED off led_state(PYB_LED_G1, 0); @@ -737,60 +812,6 @@ soft_reset: led_state(PYB_LED_G1, 0); } - // MMA testing - if (0) { - printf("1"); - mma_init(); - printf("2"); - mma_start(0x4c, 1); - printf("3"); - mma_send_byte(0); - printf("4"); - mma_stop(); - printf("5"); - mma_start(0x4c, 1); - printf("6"); - mma_send_byte(0); - printf("7"); - mma_restart(0x4c, 0); - for (int i = 0; i <= 0xa; i++) { - int data; - if (i == 0xa) { - data = mma_read_nack(); - } else { - data = mma_read_ack(); - } - printf(" %02x", data); - } - printf("\n"); - - mma_start(0x4c, 1); - mma_send_byte(7); // mode - mma_send_byte(1); // active mode - mma_stop(); - - for (;;) { - sys_tick_delay_ms(500); - - mma_start(0x4c, 1); - mma_send_byte(0); - mma_restart(0x4c, 0); - for (int i = 0; i <= 3; i++) { - int data; - if (i == 3) { - data = mma_read_nack(); - printf(" %02x\n", data); - } else { - data = mma_read_ack() & 0x3f; - if (data & 0x20) { - data |= 0xc0; - } - printf(" % 2d", data); - } - } - } - } - // SD card testing if (0) { //sdio_init(); diff --git a/stm/mma.c b/stm/mma.c index 02f6d38c4..48817b2d9 100644 --- a/stm/mma.c +++ b/stm/mma.c @@ -4,22 +4,39 @@ #include #include +#include "misc.h" +#include "systick.h" #include "mma.h" void mma_init(void) { RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // enable I2C1 + //gpio_pin_init(GPIOB, 6 /* B6 is SCL */, 2 /* AF mode */, 1 /* open drain output */, 1 /* 25 MHz */, 0 /* no pull up or pull down */); //gpio_pin_init(GPIOB, 7 /* B7 is SDA */, 2 /* AF mode */, 1 /* open drain output */, 1 /* 25 MHz */, 0 /* no pull up or pull down */); //gpio_pin_af(GPIOB, 6, 4 /* AF 4 for I2C1 */); //gpio_pin_af(GPIOB, 7, 4 /* AF 4 for I2C1 */); // XXX untested GPIO init! (was above code) + GPIO_InitTypeDef GPIO_InitStructure; + + // PB5 is connected to AVDD; pull high to enable MMA device + GPIOB->BSRRH = GPIO_Pin_5; // PB5 low to start with + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + // PB6=SCL, PB7=SDA GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOB, &GPIO_InitStructure); + + // alternate functions for SCL and SDA GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1); @@ -43,6 +60,11 @@ void mma_init(void) { // enable the I2C peripheral I2C1->CR1 |= I2C_CR1_PE; + // wait 20ms, then turn on AVDD, then wait 20ms again; this seems to work, but maybe can decrease delays + sys_tick_delay_ms(20); + GPIOB->BSRRL = GPIO_Pin_5; + sys_tick_delay_ms(20); + // set START bit in CR1 to generate a start cond! } @@ -58,27 +80,47 @@ void mma_restart(uint8_t addr, int write) { I2C1->CR1 |= I2C_CR1_START; // wait for BUSY, MSL and SB --> Slave has acknowledged start condition + uint32_t timeout = 1000000; while ((i2c_get_sr() & 0x00030001) != 0x00030001) { + if (--timeout == 0) { + printf("timeout in mma_restart\n"); + return; + } } if (write) { // send address and write bit I2C1->DR = (addr << 1) | 0; // wait for BUSY, MSL, ADDR, TXE and TRA + timeout = 1000000; while ((i2c_get_sr() & 0x00070082) != 0x00070082) { + if (--timeout == 0) { + printf("timeout in mma_restart write\n"); + return; + } } } else { // send address and read bit I2C1->DR = (addr << 1) | 1; // wait for BUSY, MSL and ADDR flags + timeout = 1000000; while ((i2c_get_sr() & 0x00030002) != 0x00030002) { + if (--timeout == 0) { + printf("timeout in mma_restart read\n"); + return; + } } } } void mma_start(uint8_t addr, int write) { // wait until I2C is not busy + uint32_t timeout = 1000000; while (I2C1->SR2 & I2C_SR2_BUSY) { + if (--timeout == 0) { + printf("timeout in mma_start\n"); + return; + } } // do rest of start @@ -89,11 +131,11 @@ void mma_send_byte(uint8_t data) { // send byte I2C1->DR = data; // wait for TRA, BUSY, MSL, TXE and BTF (byte transmitted) - int timeout = 1000000; + uint32_t timeout = 1000000; while ((i2c_get_sr() & 0x00070084) != 0x00070084) { - if (timeout-- <= 0) { - printf("mma_send_byte timed out!\n"); - break; + if (--timeout == 0) { + printf("timeout in mma_send_byte\n"); + return; } } } @@ -102,7 +144,12 @@ uint8_t mma_read_ack(void) { // enable ACK of received byte I2C1->CR1 |= I2C_CR1_ACK; // wait for BUSY, MSL and RXNE (byte received) + uint32_t timeout = 1000000; while ((i2c_get_sr() & 0x00030040) != 0x00030040) { + if (--timeout == 0) { + printf("timeout in mma_read_ack\n"); + break; + } } // read and return data uint8_t data = I2C1->DR; @@ -115,7 +162,12 @@ uint8_t mma_read_nack(void) { // last byte should apparently also generate a stop condition I2C1->CR1 |= I2C_CR1_STOP; // wait for BUSY, MSL and RXNE (byte received) + uint32_t timeout = 1000000; while ((i2c_get_sr() & 0x00030040) != 0x00030040) { + if (--timeout == 0) { + printf("timeout in mma_read_nack\n"); + break; + } } // read and return data uint8_t data = I2C1->DR;