-
Notifications
You must be signed in to change notification settings - Fork 6.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
drivers: nrf: Fix nrf uarte fifo_fill function. #11475
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ struct uarte_nrfx_data { | |
uart_irq_callback_user_data_t cb; /**< Callback function pointer */ | ||
void *cb_data; /**< Callback function arg */ | ||
u8_t *tx_buffer; | ||
volatile bool disable_tx_irq; | ||
#endif /* UARTE_INTERRUPT_DRIVEN */ | ||
}; | ||
|
||
|
@@ -82,7 +83,22 @@ static inline NRF_UARTE_Type *get_uarte_instance(struct device *dev) | |
static void uarte_nrfx_isr(void *arg) | ||
{ | ||
struct device *dev = arg; | ||
const struct uarte_nrfx_data *data = get_dev_data(dev); | ||
struct uarte_nrfx_data *data = get_dev_data(dev); | ||
NRF_UARTE_Type *uarte = get_uarte_instance(dev); | ||
|
||
if (data->disable_tx_irq && | ||
nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_ENDTX)) { | ||
nrf_uarte_int_disable(uarte, NRF_UARTE_INT_ENDTX_MASK); | ||
|
||
/* If there is nothing to send, driver will save an energy | ||
* when TX is stopped. | ||
*/ | ||
nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STOPTX); | ||
|
||
data->disable_tx_irq = false; | ||
|
||
return; | ||
} | ||
|
||
if (data->cb) { | ||
data->cb(data->cb_data); | ||
|
@@ -275,6 +291,9 @@ static int uarte_nrfx_fifo_fill(struct device *dev, | |
struct uarte_nrfx_data *data = get_dev_data(dev); | ||
const struct uarte_nrfx_config *config = get_dev_config(dev); | ||
|
||
if (!nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_ENDTX)) { | ||
return 0; | ||
} | ||
|
||
if (len > config->tx_buff_size) { | ||
len = config->tx_buff_size; | ||
|
@@ -320,29 +339,32 @@ static int uarte_nrfx_fifo_read(struct device *dev, | |
static void uarte_nrfx_irq_tx_enable(struct device *dev) | ||
{ | ||
NRF_UARTE_Type *uarte = get_uarte_instance(dev); | ||
struct uarte_nrfx_data *data = get_dev_data(dev); | ||
|
||
nrf_uarte_int_enable(uarte, NRF_UARTE_INT_ENDTX_MASK); | ||
data->disable_tx_irq = false; | ||
} | ||
|
||
/** Interrupt driven transfer disabling function */ | ||
static void uarte_nrfx_irq_tx_disable(struct device *dev) | ||
{ | ||
NRF_UARTE_Type *uarte = get_uarte_instance(dev); | ||
|
||
nrf_uarte_int_disable(uarte, NRF_UARTE_INT_ENDTX_MASK); | ||
|
||
/* If there is nothing to send, driver will save an energy | ||
* when TX is stopped. | ||
*/ | ||
nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STOPTX); | ||
struct uarte_nrfx_data *data = get_dev_data(dev); | ||
/* TX IRQ will be disabled after current transmission is finished */ | ||
data->disable_tx_irq = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should also clear this flag in |
||
} | ||
|
||
/** Interrupt driven transfer ready function */ | ||
static int uarte_nrfx_irq_tx_ready_complete(struct device *dev) | ||
{ | ||
NRF_UARTE_Type *uarte = get_uarte_instance(dev); | ||
|
||
return nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_ENDTX); | ||
/* ENDTX flag is always on so that ISR is called when we enable TX IRQ. | ||
* Because of that we have to explicitly check if ENDTX interrupt is | ||
* enabled, otherwise this function would always return true no matter | ||
* what would be the source of interrupt. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I don't get it. This function is supposed to return true exactly when the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the application it is a problem if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Then perhaps the application should be corrected. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Application assumes correctly that it is allowed to send data with When application is used with UART (not UARTE) this works as expected. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It does. If it doesn't that's bug. Indeed, uart_irq_tx_ready() should be gated on on interrupts being enabled. Well, I don't know if there're some apps which can be fooled otherwise, but we can't dismiss that. The issue, there's single ISR for both UART RX and TX (and for errors, about which a few people remember). So, ISR can be called by RX interrupt, and should not be wrongly doing TX actions if TX is effectively disabled (and if TX interrupt is disabled, then effectively TX is disabled). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I created an issue (#11535) for clarification of this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR fixes current issues with nrf uarte driver acting differently than nrf uart driver. I agree that API has to be clarified and it should be discussed, but changes in this PR don't affect it and are needed now. Also there is ongoing work on new API #10820 which will eventually make current interrupt driven API obsolete and we should focus on that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm +1 on this logic, let me approve. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. Let's go on with this fix for now. |
||
*/ | ||
return nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_ENDTX) && | ||
nrf_uarte_int_enable_check(uarte, NRF_UARTE_INT_ENDTX_MASK); | ||
} | ||
|
||
static int uarte_nrfx_irq_rx_ready(struct device *dev) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the type should be a atomic_t type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only independent load and store operations are used which are itself atomic, there is no need for atomic type.