Skip to content

Commit

Permalink
cpu/stm32/usbdev_fs: fix EP_REG(x) assignment for toggleable bits
Browse files Browse the repository at this point in the history
EP_REG(x) registers have a total of 6 toggleable bits. Those bits can only be toggled if we write a one to it, otherwise writing a zero has no effect
This commit fixes all the access to these registers to prevent from modifying these bits when not needed

Signed-off-by: Dylan Laduranty <[email protected]>
  • Loading branch information
dylad committed Apr 7, 2023
1 parent 164331e commit c03b951
Showing 1 changed file with 25 additions and 15 deletions.
40 changes: 25 additions & 15 deletions cpu/stm32/periph/usbdev_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ typedef struct {
#error "_PMA_ACCESS_SCHEME is not defined"
#endif

/* Bit mask containing all toggleable bits in a EP_REG(x) register */
#define _EP_REG_TOGGLE_ONLY_BITS_MASK (USB_EP_DTOG_TX | USB_EP_DTOG_RX | \
USB_EPTX_STAT | USB_EPRX_STAT )

#define EP_DESC ((ep_buf_desc_t*)USB1_PMAADDR)
#define EP_REG(x) (*((volatile uint32_t*) (((uintptr_t)(USB)) + (4*x))))

Expand Down Expand Up @@ -313,8 +317,9 @@ void USBDEV_ISR(void) {
unsigned epnum = irq_status & 0x000F;
usbdev_ep_t *ep = (irq_status & USB_ISTR_DIR) ? &_ep_out[epnum] : &_ep_in[epnum];
/* get type and add endpoint address */
uint16_t reg = _type_to_reg(ep->type) | ep->num;

uint16_t reg = (_type_to_reg(ep->type) | ep->num);
/* Avoid toggling by mistake these bits */
CLRBIT(reg, (_EP_REG_TOGGLE_ONLY_BITS_MASK));
if (irq_status & USB_ISTR_DIR) {
/* Clear RX CTR by writing 0, avoid clear TX CTR so leave it to one */
EP_REG(epnum) = reg | USB_EP_CTR_TX;
Expand Down Expand Up @@ -422,8 +427,10 @@ static bool _ep_check(stm32_usbdev_fs_t *usbdev, unsigned idx,
static void _ep_enable(usbdev_ep_t *ep)
{
uint16_t reg = EP_REG(ep->num);
/* Avoid modification of the following registers */
/* Avoid modification of the following bits in the register as writing
1 has no effect on theses bits */
SETBIT(reg, USB_EP_CTR_RX | USB_EP_CTR_TX);
CLRBIT(reg, USB_EP_DTOG_RX | USB_EP_DTOG_TX);
if (ep->dir == USB_EP_DIR_OUT) {
_set_ep_out_status(&reg, USB_EP_RX_NAK);
/* Avoid toggling the other direction */
Expand All @@ -441,7 +448,8 @@ static void _ep_enable(usbdev_ep_t *ep)
static void _ep_disable(usbdev_ep_t *ep)
{
uint16_t reg = EP_REG(ep->num);
/* Avoid modification of the following registers */
/* Avoid modification of the following bits in the register as writing
1 has no effect on theses bits */
SETBIT(reg, USB_EP_CTR_RX | USB_EP_CTR_TX);

if (ep->dir == USB_EP_DIR_OUT) {
Expand Down Expand Up @@ -580,16 +588,17 @@ static void _usbdev_esr(usbdev_t *dev)

static void _usbdev_ep_init(usbdev_ep_t *ep)
{
uint16_t reg = EP_REG(ep->num);
/* Set endpoint type */
uint16_t reg = _type_to_reg(ep->type);
/* Keep previous state if already set */
reg |= EP_REG(ep->num) & (USB_EPTX_STAT | USB_EPRX_STAT);
_set_ep_out_status(&reg, USB_EP_RX_VALID);
reg &= ~(USB_EP_TYPE_MASK);
reg |= _type_to_reg(ep->type);
/* Keep the state ouf the other endpoint direction if already sets */
CLRBIT(reg, _EP_REG_TOGGLE_ONLY_BITS_MASK);
/* Assign EP address */
reg |= (ep->num & 0x000F);
/* Ensure interrupts are cleared */
reg |= USB_EP_CTR_RX | USB_EP_CTR_TX;

reg &= ~(USB_EP_CTR_RX | USB_EP_CTR_TX);
/* Write the configuration to the register */
EP_REG(ep->num) = reg;
if (ep->dir == USB_EP_DIR_IN) {
EP_DESC[ep->num].addr_tx = _ep_in_buf[ep->num];
Expand Down Expand Up @@ -653,7 +662,8 @@ static int _usbdev_ep_get(usbdev_ep_t *ep, usbopt_ep_t opt,
static void _ep_set_stall(usbdev_ep_t *ep, usbopt_enable_t enable)
{
uint16_t reg = EP_REG(ep->num);
/* Avoid modification of the following registers */
/* Avoid modification of the following bits in the register as writing
1 has no effect on theses bits */
SETBIT(reg, USB_EP_CTR_RX | USB_EP_CTR_TX);

if (ep->dir == USB_EP_DIR_IN) {
Expand Down Expand Up @@ -742,11 +752,12 @@ static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t* buf, size_t len)
{
unsigned irq = irq_disable();
uint16_t reg = EP_REG(ep->num);
/* Avoid modification of the following registers */
/* Avoid modification of the following bits in the register as writing
1 has no effect on theses bits */
SETBIT(reg, USB_EP_CTR_RX | USB_EP_CTR_TX);
if (ep->dir == USB_EP_DIR_OUT) {
_set_ep_out_status(&reg, USB_EP_RX_VALID);
_set_ep_in_status(&reg, USB_EP_TX_NAK);
CLRBIT(reg, USB_EPTX_STAT);
if (len == 0) {
len = ep->len;
}
Expand All @@ -761,8 +772,7 @@ static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t* buf, size_t len)
_app_pbuf[ep->num] = buf;
} else {
_set_ep_in_status(&reg, USB_EP_TX_VALID);
_set_ep_out_status(&reg, USB_EP_RX_VALID);

CLRBIT(reg, USB_EPRX_STAT);
/* Transfer IN buffer content to USB PMA SRAM */
uint16_t* pma_ptr = (uint16_t *)(USB1_PMAADDR +
(EP_DESC[ep->num].addr_tx * _PMA_ACCESS_STEP_SIZE));
Expand Down

0 comments on commit c03b951

Please sign in to comment.