Fix clock divider calculation

pull/249/head
Jeroen Domburg 2017-01-11 13:01:48 +08:00
rodzic 69a7cfa976
commit a98d07d650
1 zmienionych plików z 36 dodań i 24 usunięć

Wyświetl plik

@ -389,39 +389,51 @@ esp_err_t spi_bus_remove_device(spi_device_handle_t handle)
return ESP_OK; return ESP_OK;
} }
static int spi_freq_for_pre_n(int fapb, int pre, int n) {
return (fapb / (pre * n));
}
static void spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) { static void spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) {
int pre, n, h, l; int pre, n, h, l;
//In hw, n, h and l are 1-32, pre is 0-8K. Value written to register is one lower than used value.
if (hz>(fapb/2)) { //In hw, n, h and l are 1-32, pre is 1-8K. Value written to register is one lower than used value.
//Can only solve this using fapb directly. if (hz>((fapb/4)*3)) {
//Using Fapb directly will give us the best result here.
hw->clock.clkcnt_l=0; hw->clock.clkcnt_l=0;
hw->clock.clkcnt_h=0; hw->clock.clkcnt_h=0;
hw->clock.clkcnt_n=0; hw->clock.clkcnt_n=0;
hw->clock.clkdiv_pre=0; hw->clock.clkdiv_pre=0;
hw->clock.clk_equ_sysclk=1; hw->clock.clk_equ_sysclk=1;
} else { } else {
//For best duty cycle resolution, we want n to be as close to 32 as possible. //For best duty cycle resolution, we want n to be as close to 32 as possible, but
//ToDo: //we also need a pre/n combo that gets us as close as possible to the intended freq.
//This algo could use some tweaking; at the moment it either fixes n to 32 and //To do this, we bruteforce n and calculate the best pre to go along with that.
//uses the prescaler to get a suitable division factor, or sets the prescaler to 0 //If there's a choice between pre/n combos that give the same result, use the one
//and uses n to set a value. In practice, sometimes a better result can be //with the higher n.
//obtained by setting both n and pre to well-chosen valued... ToDo: fix up some algo to int bestn=-1;
//do this automatically (worst-case: bruteforce n/pre combo's) - JD int bestpre=-1;
//Also ToDo: int besterr=hz;
//The ESP32 has a SPI_CK_OUT_HIGH_MODE and SPI_CK_OUT_LOW_MODE register; it looks like we can int errval;
//use those to specify the duty cycle in a more precise way. Figure out how to use these. - JD for (n=1; n<33; n++) {
n=(fapb/(hz*32)); //Effectively, this does pre=round((fapb/n)/hz).
if (n>32) { pre=((fapb/n)+(hz/2))/hz;
//Need to use prescaler if (pre<0) pre=0;
n=32; if (pre>8192) pre=8192;
errval=abs(spi_freq_for_pre_n(fapb, pre, n)-hz);
if (errval<=besterr) {
besterr=errval;
bestn=n;
bestpre=pre;
}
} }
if (n<32) {
//No need for prescaler. n=bestn;
n=(fapb/hz); pre=bestpre;
} l=n;
pre=(fapb/n)/hz; //This effectively does round((duty_cycle*n)/256)
h=n; h=(duty_cycle*n+127)/256;
l=(((256-duty_cycle)*n+127)/256); if (h<=0) h=1;
hw->clock.clk_equ_sysclk=0; hw->clock.clk_equ_sysclk=0;
hw->clock.clkcnt_n=n-1; hw->clock.clkcnt_n=n-1;
hw->clock.clkdiv_pre=pre-1; hw->clock.clkdiv_pre=pre-1;