• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Настройка I2S, нужна помощь

clinkme

Member
Планирую использовать блок I2S для генерации несущей для IR-передатчика, как в примере espressif.
Они предлагают использовать GPIO2 (I2SO_WS), GPIO14 (I2SI_WS), GPIO13(I2SI_BCK), при этом расчет в примере делается для 38 кГц.
Перебирал делители и так и эдак, но так и не понял идею расчета (например, что надо изменить, чтобы получить несущую 36 или 40 кГц вместо 38?).


Код:
/******************************************************************************
 * FunctionName : gen_carrier_clk
 * Description  : gen 38khz carrier clk
 * Parameters  : NONE
 * Returns  :  NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
gen_carrier_clk()
{
   //ENABLE I2S CLK SOURCE
   rom_i2c_writeReg_Mask(i2c_bbpll, i2c_bbpll_hostid, i2c_bbpll_en_audio_clock_out, i2c_bbpll_en_audio_clock_out_msb, i2c_bbpll_en_audio_clock_out_lsb, 1);
   //CONFIG AS I2S
#if (IR_NEC_TX_IO_MUX==PERIPHS_IO_MUX_GPIO2_U)
   //set i2s clk freq  GPIO2!!!
   WRITE_PERI_REG(I2SCONF,  READ_PERI_REG(I2SCONF) & 0xf0000fff|
    ( (( 62&I2S_BCK_DIV_NUM )<<I2S_BCK_DIV_NUM_S)|
    ((2&I2S_CLKM_DIV_NUM)<<I2S_CLKM_DIV_NUM_S)|
    ((1&I2S_BITS_MOD  )  <<  I2S_BITS_MOD_S )  )  );

   WRITE_PERI_REG(IR_NEC_TX_IO_MUX, (READ_PERI_REG(IR_NEC_TX_IO_MUX)&0xfffffe0f)| (0x1<<4) );
   WRITE_PERI_REG(0x60000e08, READ_PERI_REG(0x60000e08) & 0xfffffdff | (0x1<<8) ); //i2s tx  start
#endif

#if (IR_NEC_TX_IO_MUX==PERIPHS_IO_MUX_MTMS_U)
   //set i2s clk freq
   WRITE_PERI_REG(I2SCONF,  READ_PERI_REG(I2SCONF) & 0xf0000fff|
    ( (( 62&I2S_BCK_DIV_NUM )<<I2S_BCK_DIV_NUM_S)|  
    ((2&I2S_CLKM_DIV_NUM)<<I2S_CLKM_DIV_NUM_S)|   
    ((1&I2S_BITS_MOD  )  <<  I2S_BITS_MOD_S )  )  );

   WRITE_PERI_REG(IR_NEC_TX_IO_MUX, (READ_PERI_REG(IR_NEC_TX_IO_MUX)&0xfffffe0f)| (0x1<<4) );
   WRITE_PERI_REG(0x60000e08, READ_PERI_REG(0x60000e08) & 0xfffffdff | (0x2<<8) ) ;//i2s rx  start
#endif
#if (IR_NEC_TX_IO_MUX==PERIPHS_IO_MUX_MTCK_U)
   //set i2s clk freq GPIO13!!!
   WRITE_PERI_REG(I2SCONF,  READ_PERI_REG(I2SCONF) & 0xf0000fff|
    ( (( 63&I2S_BCK_DIV_NUM )<<I2S_BCK_DIV_NUM_S)|
    ((63&I2S_CLKM_DIV_NUM)<<I2S_CLKM_DIV_NUM_S)|
    ((1&I2S_BITS_MOD  )  <<  I2S_BITS_MOD_S )  )  );

   WRITE_PERI_REG(IR_NEC_TX_IO_MUX, (READ_PERI_REG(IR_NEC_TX_IO_MUX)&0xfffffe0f)| (0x1<<4) );
   WRITE_PERI_REG(0x60000e08, READ_PERI_REG(0x60000e08) & 0xfffffdff | (0x2<<8) ) ;//i2s rx  start
#endif
#if (IR_NEC_TX_IO_MUX==PERIPHS_IO_MUX_MTDO_U)
   //set i2s clk freq
   WRITE_PERI_REG(I2SCONF,  READ_PERI_REG(I2SCONF) & 0xf0000fff|
    ( (( 63&I2S_BCK_DIV_NUM )<<I2S_BCK_DIV_NUM_S)|
    ((63&I2S_CLKM_DIV_NUM)<<I2S_CLKM_DIV_NUM_S)|
    ((1&I2S_BITS_MOD  )  <<  I2S_BITS_MOD_S )));

   WRITE_PERI_REG(IR_NEC_TX_IO_MUX, (READ_PERI_REG(IR_NEC_TX_IO_MUX)&0xfffffe0f)| (0x1<<4) );
   WRITE_PERI_REG(0x60000e08, READ_PERI_REG(0x60000e08) & 0xfffffdff | (0x1<<8) ); //i2s tx  start
#endif
}
 

pvvx

Активный участник сообщества
Там завязка с I2S_BITS_MOD.
Для вашего варианта (куска кода) выходит, к примеру I2S_BCK_DIV_NUM =16, I2S_CLKM_DIV_NUM=8 -> I2SO_BCK (GPOI15) = 1.25MHz, I2SO_WS (GPIO2) = 1250/17/2 = 36.76 kHz
I2S_BCK_DIV_NUM = 43, I2S_CLKM_DIV_NUM= 3 -> I2SO_BCK (GPOI15) = 1.241MHz, I2SO_WS (GPIO2) = 36.48 kHz

http://bbs.espressif.com/viewtopic.php?t=958
 
Последнее редактирование:

clinkme

Member
Т.е. окончательная формула для частоты
будет выглядеть так (для сигнала _WS):
Код:
freq = (160000000 / I2S_BCK_DIV_NUM / I2S_CLKM_DIV_NUM) / 2*(16+I2S_BITS_MOD)
И минимальная частота получается около 800 Hz. Можно еще куда применить.
 

pvvx

Активный участник сообщества
Не совcем так, но примерно для данного случая "(1&I2S_BITS_MOD)" :)
Перепишите пример для заливки в IRAM и заливайте в память из компилятора без прошивки flash и всяких SDK хоть тысчи раз с разными вариантами.
Подключите логер или многоканальный осел и наблюдайте. Я так и сделал.
Примерный код инициализации PLL и других мелочей для старта теста из IRAM
Код:
#include "bios.h"
#include "osapi.h"
#include "os_type.h"
#include "hw/esp8266.h"
#include "hw/eagle_soc.h"
#include "hw/uart_register.h"
//=============================================================================
void tests(void)
{
    ets_set_idle_cb(NULL, NULL);
    ets_intr_unlock();
  // ваш код
}
//=============================================================================
// Стандартный вывод putc (UART1)
//-----------------------------------------------------------------------------
void uart1_write_char(char c)
{
    if (c != '\r') {
        do {
            MEMW();
            if(((UART1_STATUS >> UART_TXFIFO_CNT_S) & UART_TXFIFO_CNT) <= 125) break;
        } while(1);
        if (c != '\n') UART1_FIFO = c;
        else {
           UART1_FIFO = '\r';
           UART1_FIFO = '\n';
        }
    }
}
void uart1_init(uint32 baud, uint32 parity)
{
    GPIO2_MUX = (1<<GPIO_MUX_FUN_BIT1);
    UART1_CLKDIV = ((ets_get_cpu_frequency()  * 1000000) >> (CLK_PRE_PORT & 1)) / baud;
    UART1_CONF0 = 0x1C | (parity & 3) | ((parity & UART_PARITY_EN)? 0 : 2 << UART_STOP_BIT_NUM_S);
    os_install_putc1((void *)uart1_write_char); // install uart1 putc callback
}

extern uint8 _bss_start;
extern uint8 _bss_end;

void call_user_start(void)
{
    IO_RTC_4 = 0; // отключить WiFi
    GPIO0_MUX = 0; // отключить вывод Q_CLK
    // Очистка сегмента bss //    mem_clr_bss();
    uint8 * ptr = &_bss_start;
    while(ptr < &_bss_end) *ptr++ = 0;
    // CLK CPU 160 MHz (настройка pll на 80MHz при кварце 26MHz)
    rom_i2c_writeReg(103, 4, 1, 136);
    rom_i2c_writeReg(103, 4, 2, 145);
    CLK_PRE_PORT |= 1;
    ets_update_cpu_frequency(80 * 2);
    ets_timer_init();
    uart1_init(230400, 0);
    ets_printf("\nStart.\n");
    IO_RTC_4 |= 0x80000000; // переключить источник тактирования i2s и т.д. к PLL
    ets_delay_us(100000);
    ets_set_idle_cb(tests, NULL);
    ets_run();
}
Хидеры из https://github.com/pvvx/esp8266web/tree/master/include
 
Последнее редактирование:
Сверху Снизу