Add working MMA support.
This commit is contained in:
parent
d2c1a732e5
commit
6f08f8ce51
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
129
stm/main.c
129
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();
|
||||
|
|
62
stm/mma.c
62
stm/mma.c
|
@ -4,22 +4,39 @@
|
|||
#include <stm32f4xx_rcc.h>
|
||||
#include <stm32f4xx_gpio.h>
|
||||
|
||||
#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;
|
||||
|
|
Loading…
Reference in New Issue