Handle APB frequency change (#2250)

* Add APB change callbacks and move cpu code to own file

* Properly set esp_timer and FreeRTOS tick dividers

* Improve updated devisors

* No need to update REF_TICK yet

* Add initial handling for UART baud change

* fix uartWriteBuf and uartDetectBaudrate

* trigger callbacks even when APB did not change

* toggle UART ISR on CPU change

* add XTAL freq getter and add cpu freq validation

* Support CPU frequency changes in I2C (#2287)

**esp32-hal-i2c.c**
* add callback for cpu frequency changes
* adjust fifo thresholds based on cpu frequency and i2c bus frequency
* reduce i2c bus frequency if differential is too small
**Wire.h**
* version to 1.1.0

* Implement clock change for the other peripherals

* remove bad CPU clock values from the menu

* Add note to CPU freqs that support WiFi and BT
This commit is contained in:
Me No Dev
2019-01-09 10:07:54 +01:00
committed by GitHub
parent ff18a211e4
commit 2fd39b1aff
13 changed files with 484 additions and 113 deletions

View File

@ -67,6 +67,8 @@ static uart_t _uart_bus_array[3] = {
};
#endif
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
static void IRAM_ATTR _uart_isr(void *arg)
{
uint8_t i, c;
@ -216,6 +218,7 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
uartAttachTx(uart, txPin, inverted);
}
addApbChangeCallback(uart, uart_on_apb_change);
return uart;
}
@ -224,11 +227,10 @@ void uartEnd(uart_t* uart)
if(uart == NULL) {
return;
}
removeApbChangeCallback(uart, uart_on_apb_change);
UART_MUTEX_LOCK();
if(uart->queue != NULL) {
uint8_t c;
while(xQueueReceive(uart->queue, &c, 0));
vQueueDelete(uart->queue);
uart->queue = NULL;
}
@ -248,8 +250,6 @@ size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
UART_MUTEX_LOCK();
if(uart->queue != NULL) {
uint8_t c;
while(xQueueReceive(uart->queue, &c, 0));
vQueueDelete(uart->queue);
uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
if(uart->queue == NULL) {
@ -319,10 +319,9 @@ void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
}
UART_MUTEX_LOCK();
while(len) {
while(len && uart->dev->status.txfifo_cnt < 0x7F) {
uart->dev->fifo.rw_byte = *data++;
len--;
}
while(uart->dev->status.txfifo_cnt == 0x7F);
uart->dev->fifo.rw_byte = *data++;
len--;
}
UART_MUTEX_UNLOCK();
}
@ -359,13 +358,49 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
UART_MUTEX_UNLOCK();
}
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb)
{
uart_t* uart = (uart_t*)arg;
if(ev_type == APB_BEFORE_CHANGE){
UART_MUTEX_LOCK();
//disabple interrupt
uart->dev->int_ena.val = 0;
uart->dev->int_clr.val = 0xffffffff;
// read RX fifo
uint8_t c;
BaseType_t xHigherPriorityTaskWoken;
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
c = uart->dev->fifo.rw_byte;
if(uart->queue != NULL && !xQueueIsQueueFullFromISR(uart->queue)) {
xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken);
}
}
// wait TX empty
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
} else {
//todo:
// set baudrate
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
uint32_t baud_rate = ((old_apb<<4)/clk_div);
clk_div = ((new_apb<<4)/baud_rate);
uart->dev->clk_div.div_int = clk_div>>4 ;
uart->dev->clk_div.div_frag = clk_div & 0xf;
//enable interrupts
uart->dev->int_ena.rxfifo_full = 1;
uart->dev->int_ena.frm_err = 1;
uart->dev->int_ena.rxfifo_tout = 1;
uart->dev->int_clr.val = 0xffffffff;
UART_MUTEX_UNLOCK();
}
}
uint32_t uartGetBaudRate(uart_t* uart)
{
if(uart == NULL) {
return 0;
}
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
return ((UART_CLK_FREQ<<4)/clk_div);
return ((getApbFrequency()<<4)/clk_div);
}
static void IRAM_ATTR uart0_write_char(char c)
@ -505,7 +540,7 @@ uartDetectBaudrate(uart_t *uart)
uart->dev->auto_baud.en = 0;
uartStateDetectingBaudrate = false; // Initialize for the next round
unsigned long baudrate = UART_CLK_FREQ / divisor;
unsigned long baudrate = getApbFrequency() / divisor;
static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400};