Аксель и libopencm3

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
NotoriousCoder)
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вс июл 30, 2023 14:12:33

Аксель и libopencm3

Сообщение NotoriousCoder) »

Здравствуйте, товарищи! Задавал вопрос на другом форуме, не отвечают, задам здесь (если еще всем не надоел :)) )

Пытаюсь заставить работать аксель LSM303DLHC на плате stm32f3discovery. Неприятным сюрпризом оказалось, что i2c интерфейс на f3 сильно отличается от других stm-ок и по этой причине я решил использовать libopencm3 (вернее небольшую ее часть, которую чуть-чуть изменил). Проблема наступает тогда, когда я пытаюсь прочитать значения, представленные 2мя байтами.

Поясню. Чтение регистра (любой регистр представленный одним байтом, условно CTRL_REG1_A ) успешно отдает мне ожидаемые значения, однако чтения OUT_X_L_A вместе с OUT_X_H_A ( и им подобных по осям Y и Z) возвращает всегда 0, как не крути плату. Изначально я делал подобно тому, как было в примерах самой либы. Пример из либы:

Код: Выделить всё

cmd = ACC_STATUS;
i2c_transfer7(I2C1, I2C_ACC_ADDR, &cmd, 1, &data, 1);
cmd = ACC_OUT_X_L_A;
i2c_transfer7(I2C1, I2C_ACC_ADDR, &cmd, 1, &data, 1);
acc_x = data;
cmd = ACC_OUT_X_H_A;
i2c_transfer7(I2C1, I2C_ACC_ADDR, &cmd, 1, &data, 1);
acc_x |= ((uint16_t)data << 8);
К сожалению, такой вариант не сработал.

Далее я внимательно читаю документацию на акселерометр и вижу там следующее:
In order to read multiple bytes, it is necessary to assert the most significant bit of the sub-
address field. In other words, SUB(7) must be equal to 1 while SUB(6-0) represents the
address of the first register to be read.


После чего пишу вот так:

Код: Выделить всё

#define I2C_MULTIPLE_RWBIT   (uint8_t)0x80
 
uint8_t cmd;
uint8_t data[6];
cmd = LSM303_OUT_X_L_A | I2C_MULTIPLE_RWBIT;
/* 6 is cause 2 byte * 3 value * xyz */
i2c1_transfer7(I2C_ACC_ADDR, &cmd, 1, &data, 6);
*X= (int16_t)(data[1] << 8 | data[0]);
*Y = (int16_t)(data[3] << 8 | data[2]);
*Z = (int16_t)(data[5] << 8 | data[4]);
Данный вариант также не работает, не работают и многие подобные ему. Знающие люди, подскажите, пожалуйста, как прочитать значение представленное двумя байтами из акселерометра?
P.S. На всякий случай код функции i2c1_transfer7(), т.к. закрадывается нехорошее подозрение на счет весьма непонятного FIXME, оставленного разработчиками:

Код: Выделить всё

void i2c1_transfer7(uint8_t addr, const uint8_t *w, size_t wn, uint8_t *r, size_t rn)
{
	/*  waiting for busy is unnecessary. read the RM */
	if (wn) {
		i2c1_set_7bit_address(addr);
		i2c1_set_write_transfer_dir();
		i2c1_set_bytes_to_transfer(wn);
		if (rn) {
			i2c1_disable_autoend();
		} else {
			i2c1_enable_autoend();
		}
		i2c1_send_start();

		while (wn--) {
			bool wait = true;
			while (wait) {
				if (i2c1_transmit_int_status()) {
					wait = false;
				}
				while (i2c1_nack()); /* FIXME Some error */
			}
			i2c1_send_data(*w++);
		}
		/* not entirely sure this is really necessary.
		 * RM implies it will stall until it can write out the later bits
		 */
		if (rn) {
			while (!i2c1_transfer_complete());
		}
	}

	if (rn) {
		/* Setting transfer properties */
		i2c1_set_7bit_address(addr);
		i2c1_set_read_transfer_dir();
		i2c1_set_bytes_to_transfer(rn);
		/* start transfer */
		i2c1_send_start();
		/* important to do it afterwards to do a proper repeated start! */
		i2c1_enable_autoend();

		for (size_t i = 0; i < rn; i++) {
			while (i2c1_received_data() == 0);
			r[i] = i2c1_get_data();
		}
	}
}
Добавлено after 6 minutes 35 seconds:
Наверное, стоит закрепить ссылку на даташит https://www.st.com/en/mems-and-sensors/lsm303dlhc.html
Вложения
lsm303dlhc.pdf
(813.52 КБ) 46 скачиваний
NotoriousCoder)
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вс июл 30, 2023 14:12:33

Re: Аксель и libopencm3

Сообщение NotoriousCoder) »

Так, товарищи, самостоятельно решил проблему. Не могу предположить, где конкретно заключалась ошибка, поскольку переписал все на cmsis и таки заработало, хоть и не сразу. Просто хочется отметить, что libopencm3, не смотря на хвалу некоторых оказалась неспособной решить свою задачу и остаются вопросы на счет другой перефирии, например, куда более сложного usb. "Плюсом" идут еще и нерабочие примеры для самой же либы и непонятный FIXME в коде. Вероятно, всё таки писать на cmsis в конечном итоге лучше и удобнее.

P.S. можно ли как то закрыть свой тред?
Ответить

Вернуться в «ARM»