RS
Решил я тут запилить sdio для stm32 в libopencm3
Сделал всё по её спорным канонам, запись в регистр разбита на OVER_9999 отдельных функций. Типа:
...
void sdio_set_cpsm_long_response_mode(uint32_t sdio) {
SDIO_CMD(sdio) |= SDIO_CMD_LONGRESP;
}
void sdio_set_cpsm_short_response_mode(uint32_t sdio) {
SDIO_CMD(sdio) &= ~SDIO_CMD_LONGRESP;
}
void sdio_set_command_index(uint32_t sdio, uint8_t index) {
SDIO_CMD(sdio) = (SDIO_CMD(sdio) & ~(SDIO_CMD_CMDINDEX_MASK << SDIO_CMD_CMDINDEX_SHIFT)) |
(index << SDIO_CMD_CMDINDEX_SHIFT);
}
...
В общем, запилил. Пытаюсь юзать. И вот не работает никак. Пол дня убил.
Чужие примеры на регистрах работают идеально. А этот на функциях - никак. При том, что делаю тоже самое.
А потом заметил одну важную деталь. В коде с регистрами они записываются сразу целиком:
SDIO_CMD(sdio) = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP | cmd;
А у меня каждый бит записывается отдельно, с чтением старых битов (как по канонам libopencm3):
SDIO_CMD(sdio) &= ~SDIO_CMD_CPSMEN;
...
SDIO_CMD(sdio) |= index;
SDIO_CMD(sdio) |= SDIO_CMD_WAITRESP;
SDIO_CMD(sdio) |= SDIO_CMD_CPSMEN;
И тут я как понял. В этой сраной AMBA PL180 регистры тормозят!
Ты в него записываешь бит, тут же читаешь - а его нет. Регистр ещё какое-то время возвращает своё старое значение.
Добавил delay после каждой функции - заработало.
У меня прям подгорело с этого. Написал тестер тормозящих регистров: https://pastebin.com/Z5xWECbt
Практически все тормозят: https://pastebin.com/4WAZ0C6g
Ну вот что это за пиздец?
Кажется теперь я знаю, почему так никто и не запилил sdio в libopencm3.
Это просто невозможно без нарушения принятых в ней подходов.