Сдаётся мне, что баги есть и в родной USB библиотеке для STM32 - USB-FS-Device development kit v3.0.1.
Это касается модификации регистров конечных точек USB_EPnR.
Регистры выглядят так:
Мягко говоря, весьма поганый набор битов с различными режимами доступа - и обычные rw, и read_and_cleared_by_writing_zero (rc_w0), и даже toggle биты, меняющие своё состояние только при записи единички...
Так вот, процедуры модификации полей TYPE и STAT работают очень просто - читают регистр, затем маскируют (AND) биты, требующие модификации и toggle биты (оставляя без изменения остальные rw и rc_w0 биты).
Затем записывают по OR нужное значение и всё это дело пишется обратно в регистр.
Вот код:
Код
#define _GetENDPOINT(bEpNum) ((uint16_t)(*(EP0REG + bEpNum)))
#define _SetENDPOINT(bEpNum,wRegValue) (*(EP0REG + bEpNum)= \
(uint16_t)wRegValue)
#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD)
#define EPTX_DTOGMASK ( 0x0030 | EPREG_MASK)
#define _SetEPTxStatus(bEpNum,wState) {\
register uint16_t _wRegVal; \
_wRegVal = _GetENDPOINT(bEpNum) & EPTX_DTOGMASK;\
/* toggle first bit ? */ \
if((EPTX_DTOG1 & wState)!= 0) \
_wRegVal ^= EPTX_DTOG1; \
/* toggle second bit ? */ \
if((EPTX_DTOG2 & wState)!= 0) \
_wRegVal ^= EPTX_DTOG2; \
_SetENDPOINT(bEpNum, _wRegVal); \
} /* _SetEPTxStatus */
void SetEPTxStatus(uint8_t bEpNum, uint16_t wState)
{
_SetEPTxStatus(bEpNum, wState);
}
Но ведь таким "макаром" можно стереть rc_w0 бит, в случае, если он был установлен железом в момент между чтением и записью регистра!
То есть читаем такоой бит как "0", затем записываем его, естественно, тоже как "0", тем самым перезаписывая новое его значение!
По идее, если я правильно понял, после маскирования биты rc_w0 надо ещё и принудительно устанавливать в "1", чтобы при записи гарантированно не потерять момент изменения состояния...
Странно, почему у фирмачей не так?
Вот даже мануал говорит, что:
Read-modify-write cycles on these registers should be avoided because between the read
and the write operations some bits could be set by the hardware and the next write would
modify them before the CPU has the time to detect the change. For this purpose, all bits
affected by this problem have an ‘invariant’ value that must be used whenever their
modification is not required. It is recommended to modify these registers with a load
instruction where all the bits, which can be modified only by the hardware, are written with
their ‘invariant’ value.Так почему же это не выполняется?
Задал этот же вопрос в ветке по АРМам, но видимо никто не в курсе...
ЗЫ: по идее, эта библиотека и куски кода из неё наверняка юзаются не в одном проекте.
И если никто не чешется - значит или баг очень маловероятен, или его нет...
В общем, пока буду, на всякий случай, дополнительно OR-ить эти два бита перед записью в регистр сразу после чтения...