• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

SPI

Andrey

New member
Кто нибудь пробовал его реально использовать в режиме мастера? Чтобы подключить какое нибудь ацп или цап или ещё что то?
С какой частотой удалось его запустить?
Микросхема имеет несколько CS сигналов. CS совпадет с MTDO, который используется для бута из флэща, И должен быть в момент старта притянут к земле. Это не есть хорошо, дергать CS почём зря. По этому я думаю лучше использовать другой CS. Например CS2. Но в SDK я не нашёл управления CS. Как можно его выбирать? Дёргать им в ручную, как бы тоже не очень красиво.
 

Perfer

New member
Сегодня целый день колупаю тему аппаратного spi на esp8266. Вот самая адекватная инофрмация:
Где-то по ссылкам есть интересный архив SPI_CODE_141204.rar стоит посмотреть
PS да и что зазорного в дерганье CS руками? режим мастера ведь ))
 

Andrey

New member
Спасибо за информацию. Я хотел бы попробовать повесить на SPI 1мгц АЦП, и не хотелось бы терять лишние такты на управление ногой. К тому же по CS у ацп начинается преобразование. и он вроде должен быть синхронизирован с тактами.
 

Perfer

New member
Поигрался с дисплеем (2.2") на чипе ili9341 по SPI. Обмен между esp8266 и дисплеем успешно проходит на частоте 10Mhz - это теоретический максимум на котором может работать ili9341.
CS дергаю сам, так как HSPI ChipSelect сидит на GND жестко. Вашу проблему с CS до конца не понял - сложно представить как CS может быт синхронизирован с тактами ))
 
Последнее редактирование:

Andrey

New member
Прошу прощения не так выразился. Не синхронизирован. В моём случае такт должен быть минимум через 6 нс после выставления CS. Я предполагал что на выставление в ручную потеряется время. А сьём с АЦП предполагался 1 мгц при тактовой SPI от 16 мгц. И не хотелось терять лишние такты. Сейчас похоже проект с SPI для меня стал не актуален, так как не могу обеспечить 1мгц такт с помощью ESP8266. Буду пытаться делать устройство с внешним контроллером и передачей по UART
На счёт CS. Вроде как специально заявлено что CS2 для всяких там АЦП и периферии. Или у вас на модуле он замкнут физически?
Ещё вопрос. Вы используете прерывание по SPI?
 

pvvx

Активный участник сообщества
В моём случае такт должен быть минимум через 6 нс после выставления CS.
От куда такие скорости у ножек порта со внутренним стробированием в 80MHz (SPI ESP8266)? Больше 20Mbits у UART биты уже сливаются на выходе ног (что говорит о стробировании выходов/входов)...
У регистров портов I/O внутренний CLK похоже ещё ниже (или строб внутренней шины) (мне пока неизвестен регистр переключения клока внутренних шин и периферии портов).
 

Perfer

New member
В моём случае такт должен быть минимум через 6 нс после выставления CS
Это не реально как не крути :)
А сьём с АЦП предполагался 1 мгц
Да и это не реально :)
Ставьте FPGA/DSP и в путь! И про SPI в этом случая я бы забыл и поскорее, в сторону чего-нибудь параллельного или LVDS. Да тут еще вопрос, допустим сняли поток данных на 1Mhz с АЦП, так их ведь еще обработать и передать дальше обычно надо, а тут эта бздюлька ESP8266 может и подвести:)
У регистров портов I/O внутренний CLK похоже ещё ниже (или строб внутренней шины) (мне пока неизвестен регистр переключения клока внутренних шин и периферии портов).
Думаю что нет такого регистра, и очень странно со стороны разработчиков ядра его иметь. Вот регистр настройки делителя частоты I/O скорее всего есть
PS если я Вас правильно понял
 

pvvx

Активный участник сообщества
Думаю что нет такого регистра, и очень странно со стороны разработчиков ядра его иметь. Вот регистр настройки делителя частоты I/O скорее всего есть
PS если я Вас правильно понял
что-то именно то. Т.к. UART идет дискретно и более 20Mbit/s сливаются биты (пропадают если 010101 на осциллографе), (у UART в SDK CLK 80MHz). При этом входы/выходы QSPI работают на 80MHz...
Чип то xtensa-lx106-elf - у него шинами, вроде...
Тут я снял работу bit-а порта http://esp8266.ru/forum/threads/tajmer-i-gpio.75/#post-1266
 
Последнее редактирование:

sharikov

Active member
На основе кода от Perfer запустил HSPI в режиме мастер, научился использовать аппаратную выдачу команд и аппаратный CS. Теперь надо подключить прерывания. Кто нибудь прерывания от HSPI использовал ?
Насколько я понял вектор у SPI и HSPI один. В примере обработчика прерываний SPI проверяют биты 4 и 7 по адресу 0x3ff00020 и если прерывание не от HSPI просто сбрасывают флаги и выходят. Странно. На основном канале висит флэш с прошивкой, к ней идут обращения. SDK что не использует прерывания ?
 

sharikov

Active member
Обнаружил что время работы обработчика прерывания hspi зависит от частоты шины spi задаваемой через регистр SPI_CLOCK.
Код по прерываниям посылает байты по spi. Время между передачами (CS="1") показывает время обработки прерываний.
Код:
/* In the master mode, it is the divider of spi_clk. So spi_clk frequency is 80MHz/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)
* In the master mode, SPI_CLKCNT_H must be floor((spi_clkcnt_N+1)/2-1)
* In the master mode, SPI_CLKCNT_L must be eqaul to spi_clkcnt_N
*/
#define SPI_CLOCK_10MHZ (((0 & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |\
        ((7 & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |\
        ((3 & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |\
        ((7 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S))
#define SPI_CLOCK_500KHZ (((2 & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |\
        ((63 & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |\
        ((31 & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |\
        ((63 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S))
#define SET_SPI_CLOCK_FAST() WRITE_PERI_REG(SPI_CLOCK(HSPI),SPI_CLOCK_10MHZ)
#define SET_SPI_CLOCK_SLOW() WRITE_PERI_REG(SPI_CLOCK(HSPI),SPI_CLOCK_500KHZ)



/*
* передает команду, потом читает read_length
* только запуск операции, прием данных в обработчике прерываний
*/
LOCAL volatile uint8_t mem1=0; // проверка влияния обращений к регистрам на скорость
void hspi_cr_start(const uint8_t cmd, const uint8_t read_length)
{
    uint32_t regvalue;
    uint16_t numberBit;

    if (mem1 ==0)
    {
        regvalue =  SPI_USR_COMMAND  /*| SPI_CS_HOLD */ ;
        if (0 != read_length)
        {
            regvalue |= SPI_USR_MISO;
            numberBit = read_length * 8 -1;
        }
        else
            numberBit = 7;

        // отключаем фазы обмена address, dummy, data_out
        //regvalue &= ~(BIT2 | SPI_USR_ADDR | SPI_USR_DUMMY | SPI_USR_MOSI /*| SPI_USR_MISO | SPI_USR_COMMAND*/); //clear bit 2 see example IoT_Demo
        WRITE_PERI_REG(SPI_USER(HSPI), regvalue);

        //set output buffer length, the buffer is the register"SPI_FLASH_C0"
        WRITE_PERI_REG(SPI_USER1(HSPI),
                ((7 & SPI_USR_MOSI_BITLEN)<<SPI_USR_MOSI_BITLEN_S)|
                ((numberBit & SPI_USR_MISO_BITLEN)<<SPI_USR_MISO_BITLEN_S));

        //SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
        // bit15-0 is cmd value.
        //0x70000000 is for 8bits cmd
        WRITE_PERI_REG(SPI_USER2(HSPI),
                ((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) |
                ((cmd & SPI_USR_COMMAND_VALUE) << SPI_USR_COMMAND_VALUE_S) );
        mem1=1;
    }
    SET_PERI_REG_MASK(SPI_CMD(HSPI), SPI_USR);   // send
}

void  __attribute__((optimize("O2"))) hspi_int_handler(void* *para)
{
    enum spi_rx_state temp_rx_state;  // локальная копия volatile переменной
    uint32_t regvalue;

    if(READ_PERI_REG(0x3ff00020) & BIT4)
    {
        //following 3 lines is to clear isr signal
        CLEAR_PERI_REG_MASK(SPI_SLAVE(SPI), 0x3ff);
        ++spicount;   // проверка работы прерываний
    }
    else
        if (READ_PERI_REG(0x3ff00020) & BIT7)
        { //bit7 is for hspi isr,

            // обнуляем все запросы прерываний spi (хотя использется только SPI_TRANS_DONE)
            CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),
                    SPI_TRANS_DONE | SPI_SLV_WR_STA_DONE |
                    SPI_SLV_RD_STA_DONE | SPI_SLV_WR_BUF_DONE |
                    SPI_SLV_RD_BUF_DONE);

            hspi_cr_start(INSTRUCTION_READ_STATUS, 62);
            mcp251x.mcp_rx_state = RXSTATE_FAST_POLLING ;
        }
}

void ICACHE_FLASH_ATTR hspi_init()
{
    uint32 regvalue;

    // gpio mux
    WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105);
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); // HSPIQ MISO
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); // HSPID MOSI
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); // CLK
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2); // CS

#if 0
    WRITE_PERI_REG(SPI_CLOCK(HSPI),
            ((1 & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
            ((3 & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |  /*In the master mode, it is the divider of spi_clk. So spi_clk frequency is 80MHz/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/
            ((1 & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |  /*In the master mode, it must be floor((spi_clkcnt_N+1)/2-1)*/
            ((3 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S));  /*In the master mode, it must be eqaul to spi_clkcnt_N*/
#else
    SET_SPI_CLOCK_FAST();
#endif

    // Disable the interrupt
    CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),
            SPI_TRANS_DONE_EN | SPI_SLV_WR_STA_DONE_EN |
            SPI_SLV_RD_STA_DONE_EN | SPI_SLV_WR_BUF_DONE_EN |
            SPI_SLV_RD_BUF_DONE_EN     );
    //register level2 isr function, which contains spi, hspi and i2s events
    ETS_SPI_INTR_ATTACH(hspi_int_handler, NULL);
    //enable level2 isr, which contains spi, hspi and i2s events
    ETS_SPI_INTR_ENABLE();
}
Результаты:
SPI_CLOCK_500KHZ (((2 & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |\
((63 & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |\
((31 & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |\
((63 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S))
Такт spi =2 .4us
Длительность обработки прерывания = 19us, период посылок =60us

SPI_CLOCK_10MHZ (((0 & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |\
((7 & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |\
((3 & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |\
((7 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S))
Такт spi = 100ns
Длительность обработки прерывания = 3us (похоже это минимум), период посылок = 55 us


Вопрос: КАК такое возможно ?
И что сделать чтобы при низкой частоте spi получить время обработки прерывания такое же как при высокой ?
 

sharikov

Active member
Добавил строб на входе и выходе обработчика прерывания. Время одинаковое при быстрой и медленной скорости spi. Задержка возникает где-то в другом месте. Надо искать дальше.
 

sharikov

Active member
Подробнее:
Код:
скорость spi SLOW (T=2.4us)
                   : ___             _________________
CS                 :    \___________/                 \_______________________
                   :                        ________
строб в прерывании : ______________________/        \____________________
                                    |      |           |
                                    | 16us | 2.6us     |
                                           |   2us  |
от перехода CS=0->1 (окончание передачи spi) до входа в обработчик прерывания spi прошло 16us,
от входа в обработчик прерывания spi до перехода CS=1->0 (начало передачи spi) прошло 2.6us



скорость spi FAST (T=0.1us)
                   : ___             ____________
CS                 :    \___________/            \_______________________
                   :                        ________
строб в прерывании : ______________________/        \____________________
                                    |      |     |
                                    |  2us |1.5us|
                                           |   2us  |
                                   
от перехода CS=0->1 (окончание передачи spi) до входа в обработчик прерывания spi прошло 2us,
от входа в обработчик прерывания spi до перехода CS=1->0 (начало передачи spi) прошло 1.5us
Видно что тормоза при низкой скорости spi возникают из-за непонятной задержки после окончания обмена spi.
 

pvvx

Активный участник сообщества
Видно что тормоза при низкой скорости spi возникают из-за непонятной задержки после окончания обмена spi.
Всегда после передачи ждет N тактов SPI-CLK и выставляет готовность (которая уже вызывает прерывание)?
Интересно сколько этот N и есть ли возможность его изменения в регистрах управления?

Оно(?):
REG_USR_DUMMY_CYCLELEN The length in spi_clk cycles of "dummy" phase. The register value shall be (cycle_num-1)
 
Последнее редактирование:

sharikov

Active member
Всегда после передачи ждет N тактов SPI-CLK и выставляет готовность (которая уже вызывает прерывание)?
Интересно сколько этот N и есть ли возможность его изменения в регистрах управления?
Оно(?):
REG_USR_DUMMY_CYCLELEN The length in spi_clk cycles of "dummy" phase. The register value shall be (cycle_num-1)
При начале передачи ждет 1 такт spi перед выставлением cs в "0".
Что происходит после передачи сказать трудно потому что сигнал готовности spi недоступен для наблюдения снаружи.
Однако время пропорционально тактовой частоте spi
Измерения длительности высокого уровня cs:
20us при периоде клока spi 2,4us
8.4us при периоде клока spi 0,8us
Время работы обработчика прерывания 1,5us
"лишняя" задержка получается
20-1,5-2,4 = 16,1us (6,7 бита)
8,4-1,5-0,8 = 6,1us (7,6 бита)

Фазу DUMMY я не включаю, попробовал изменить REG_USR_DUMMY_CYCLELEN - никаких изменений. Работают COMMAND и MISO. Разрывов в обмене или лишних импульсов нет - сколько заказал в настройках контроллера столько и выдается.
Проверил влияние количества байт в фазе MISO на задержку - не влияет (была мысль что внутри контроллер всегда работает с 32 битами данных)
 

pvvx

Активный участник сообщества
sharikov - с вашими настройками
#define SPI_CLOCK_500KHZ (((2 & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |\
((63 & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |\
((31 & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |\
((63 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S))

У меня так:
3.708us.gif
при запуске в iram (показывает счетчик прерываний в 10 секунд):

Start RAM porg
CLK = 80 MHz, Set CLK 160 MHz
HSPI ints 122511
HSPI ints 122511
HSPI ints 122512
user code done


Проверил неописанные биты. Нашлось только это:

// SPI_CTRL2:
#define SPI_CTRL2_CLK_HDIV2 (BIT(12)) // Уменьшает длительность "1" на CLK в 2 раза
#define SPI_CTRL2_CLK_HDIV4 (BIT(15)) // Уменьшает длительность "1" на CLK в 4 раза

// SPI_PIN:
//#define SPI_PIN_CLK0 (BIT(5)) // Выход CLK = "0"
#define SPI_PIN_CS_INV (BIT(6)) // инверсия сигнала CS
#define SPI_PIN_CS_CLK (BIT(11)) // сигнал на CS = CLK
#define SPI_PIN_MOSI_MISO (BIT(16)) // сигнал MISO выводится на MOSI
//#define SPI_PIN_CLK1_CS0 (BIT(19)) // CS = "0", CLK = "1"
#define SPI_PIN_CLK_INV (BIT(29)) // инверсия сигнала CLK
#define SPI_PIN_CS0 (BIT(30)) // CS = "0"
//#define SPI_PIN_CS_0 (BIT(31)) // CS = "0"

Но главное это (допишите в "spi_register.h" от esp_iot_rtos_sdk) :
Код:
#define SPI_CTRL1(i)                (REG_SPI_BASE(i) + 0xC)   // default  HSPI = 0x5fff0120 / QSPI = 0x5fff0120
#define SPI_CS_DELAY_INT                   0x0000000F // кол-во тактов SPI-CLK задержки до выставления прерывания и готовности
#define SPI_CS_DELAY_INT_S               28
У flash в SDK тоже стоит задержка в +5 тактов SPI :(

Проект в UDK с загрузкой в IRAM, чтобы не точить flash (но BIOS ESP8266 дает неверную настройку PLL, от этого и 78440 Baud и т.д. надо перепрограммировать PLL) :
 

Вложения

Последнее редактирование:

sharikov

Active member
sharikov - с вашими настройками
#define SPI_CLOCK_500KHZ (((2 & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |\
((63 & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |\
((31 & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |\
((63 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S))

У меня так:
Почем у вас с указанными настройками клок 3,7us ? должно быть 2,4 как по расчету так и фактически.

Проверил неописанные биты. Нашлось только это:
// SPI_CTRL2:
#define SPI_CTRL2_CLK_HDIV2 (BIT(12)) // Уменьшает длительность "1" на CLK в 2 раза
#define SPI_CTRL2_CLK_HDIV4 (BIT(15)) // Уменьшает длительность "1" на CLK в 4 раза
А если установить оба бита ?


// SPI_PIN:
//#define SPI_PIN_CLK0 (BIT(5)) // Выход CLK = "0"
#define SPI_PIN_CS_INV (BIT(6)) // инверсия сигнала CS
#define SPI_PIN_CS_CLK (BIT(11)) // сигнал на CS = CLK
#define SPI_PIN_MOSI_MISO (BIT(16)) // сигнал MISO выводится на MOSI
//#define SPI_PIN_CLK1_CS0 (BIT(19)) // CS = "0", CLK = "1"
#define SPI_PIN_CLK_INV (BIT(29)) // инверсия сигнала CLK
#define SPI_PIN_CS0 (BIT(30)) // CS = "0"
//#define SPI_PIN_CS_0 (BIT(31)) // CS = "0"

SPI_PIN_MOSI_MISO - куда при этом идет MOSI ? они меняются местами что ли?

Но главное это (допишите в "spi_register.h" от esp_iot_rtos_sdk) :
Код:
#define SPI_CTRL1(i)                (REG_SPI_BASE(i) + 0xC)   // default  HSPI = 0x5fff0120 / QSPI = 0x5fff0120
#define SPI_CS_DELAY_INT                   0x0000000F // кол-во тактов SPI-CLK задержки до выставления прерывания и готовности
#define SPI_CS_DELAY_INT_S               28
У flash в SDK тоже стоит задержка в +5 тактов SPI
%$##$%*#@!!!!!!
Гребаный Espressif !
Там нет случаем бита разрешения задержки до выставления прерывания ?

Добавил в инициализацию
CLEAR_PERI_REG_MASK(SPI_CTRL1(HSPI), SPI_CS_DELAY_INT << SPI_CS_DELAY_INT_S);
CS стал 6,6us. Минимальное время это 3us. Теперь лишняя задержка 3,6us. Отнимаем 1 такт при старте остается 1,2us. Те. 0,5 такта неустранимая задержка до готовности в конце обмена.

Интересно зачем они добавили задержку на flash.

Откуда вы берете недокументированные биты ?
 

pvvx

Активный участник сообщества
А если установить оба бита ?
Будут узкие палки в единичку на осциле :)
SPI_PIN_MOSI_MISO - куда при этом идет MOSI ? они меняются местами что ли?
Похоже - есть и документированный аналогичный бит.
CS стал 6,6us. Минимальное время это 3us. Теперь лишняя задержка 3,6us. Отнимаем 1 такт при старте остается 1,2us. Те. 0,5 такта неустранимая задержка до готовности в конце обмена.
Там всегда CS подымается на 2 такта SPI + та задержка в указанных битах.
Интересно зачем они добавили задержку на flash.
Чтобы работали отстойные китайские Flash.
Откуда вы берете недокументированные биты ?
Эти биты оказались документированы. В параллельной теме описал.
 

pvvx

Активный участник сообщества
Почем у вас с указанными настройками клок 3,7us ? должно быть 2,4 как по расчету так и фактически.
По тому, что запускаю из IRAM, без SDK. BIOS ROM в чипе ESP8266, как и всё от Espressif, имеет тучу ошибок и настраивает внутренние CLK неверно. SDK, при загрузке, исправляет это и многие другие функции...
 

sharikov

Active member
Решил проверить сообщение http://www.esp8266.com/viewtopic.php?f=13&t=2427&start=10#p15607
Компилятор udk, в опции компилятора добавлено -mno-serialize-volatile
Код
Код:
#define GET_CCOUNT(x) __asm__ __volatile__("rsr %0, ccount" : "=r"(x))

uint32_t calcdelta(uint32_t v1, uint32_t v2)
{
    return (v2 >= v1)? v2-v1 : v1-v2;
}

void __attribute__((optimize("O2"))) write_test(uint32_t i)
{
    uint32_t j;
    uint32_t t1, t2;
    volatile uint32_t* ptr;


    ets_uart_printf("\n--------\n");
    os_delay_us(100000);

    do
    {
        ets_uart_printf("\twithout MEMW\n");
        os_delay_us(100000);
        ptr=(volatile uint32_t *)SPI_W0(HSPI);
        __asm__ __volatile__("memw" : : : "memory");
        ets_intr_lock();
        GET_CCOUNT(t1);
        //t1=get_ccount();
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        //__asm__ __volatile__("memw" : : : "memory");
        GET_CCOUNT(t2);
        //t2=get_ccount();
        ets_intr_unlock();
        ets_uart_printf(" 8 writes: time= %d\n", calcdelta(t1, t2));
        os_delay_us(100000);

        ptr=(volatile uint32_t *)SPI_W0(HSPI);
        __asm__ __volatile__("memw" : : : "memory");
        ets_intr_lock();
        GET_CCOUNT(t1);
        //t1=get_ccount();
        /*for (j=0; j<16; j++)
            ptr[j]= i;*/
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        //__asm__ __volatile__("memw" : : : "memory");
        GET_CCOUNT(t2);
        //t2=get_ccount();
        ets_intr_unlock();
        ets_uart_printf("16 writes: time= %d\n", calcdelta(t1, t2));
        os_delay_us(100000);


        ets_uart_printf("\twith MEMW\n");
        os_delay_us(100000);
        ptr=(volatile uint32_t *)SPI_W0(HSPI);
        __asm__ __volatile__("memw" : : : "memory");
        ets_intr_lock();
        GET_CCOUNT(t1);
        //t1=get_ccount();
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        __asm__ __volatile__("memw" : : : "memory");
        GET_CCOUNT(t2);
        //t2=get_ccount();
        ets_intr_unlock();
        ets_uart_printf(" 8 writes: time= %d\n", calcdelta(t1, t2));
        os_delay_us(100000);

        ptr=(volatile uint32_t *)SPI_W0(HSPI);
        __asm__ __volatile__("memw" : : : "memory");
        ets_intr_lock();
        GET_CCOUNT(t1);
        //t1=get_ccount();
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        __asm__ __volatile__("memw" : : : "memory");
        GET_CCOUNT(t2);
        //t2=get_ccount();
        ets_intr_unlock();
        ets_uart_printf("16 writes: time= %d\n\n", calcdelta(t1, t2));
        os_delay_us(100000);
    }
    while (--i);
    ets_uart_printf("\n--------\n");
}
Результаты:
Код:
--------
   without MEMW
 8 writes: time= 22
16 writes: time= 93
   with MEMW
 8 writes: time= 75
16 writes: time= 172

   without MEMW
 8 writes: time= 22
16 writes: time= 93
   with MEMW
 8 writes: time= 75
16 writes: time= 172

   without MEMW
 8 writes: time= 22
16 writes: time= 93
   with MEMW
 8 writes: time= 75
16 writes: time= 172

   without MEMW
 8 writes: time= 22
16 writes: time= 93
   with MEMW
 8 writes: time= 75
16 writes: time= 172


--------
Какие будут мысли ?
 

pvvx

Активный участник сообщества
Компилятор udk, в опции компилятора добавлено -mno-serialize-volatile
Какие будут мысли ?
Выкинуть компилятор UDK на помойку. Он ваши *ptr++= i раскладывает на load в регистр 32-х битный адрес по смещению, потом запись по этому регистру со смещением ноль. По другому он не умеет. И вообще не умеет работать со смещениями - адрес в регистре + смещение. Только нулевое смещение. Кто-то задал такие параметры транслятору, чтобы вместо 3 байт *ptr++ выходило 10 байт с загрузкой адреса каждый раз. :mad:
Код:
void write_test(int i)
{
        volatile unsigned int * ptr=(volatile unsigned int *)0x60000240;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        *ptr++= i;
        __asm__ __volatile__("memw" : : : "memory");
}
xtensa компилятор:
Код:
60000874 <write_test>:
60000874:    ff4d31           l32r    a3, 600005a8 <_stext+0x44>
60000877:    0020c0           memw
6000087a:    106322           s32i    a2, a3, 64
6000087d:    0020c0           memw
60000880:    116322           s32i    a2, a3, 68
60000883:    0020c0           memw
60000886:    126322           s32i    a2, a3, 72
60000889:    0020c0           memw
6000088c:    136322           s32i    a2, a3, 76
6000088f:    0020c0           memw
60000892:    146322           s32i    a2, a3, 80
60000895:    0020c0           memw
60000898:    156322           s32i    a2, a3, 84
6000089b:    0020c0           memw
6000089e:    166322           s32i    a2, a3, 88
600008a1:    0020c0           memw
600008a4:    176322           s32i    a2, a3, 92
600008a7:    0020c0           memw
600008aa:    186322           s32i    a2, a3, 96
600008ad:    0020c0           memw
600008b0:    196322           s32i    a2, a3, 100
600008b3:    0020c0           memw
600008b6:    1a6322           s32i    a2, a3, 104
600008b9:    0020c0           memw
600008bc:    1b6322           s32i    a2, a3, 108
600008bf:    0020c0           memw
600008c2:    1c6322           s32i    a2, a3, 112
600008c5:    0020c0           memw
600008c8:    1d6322           s32i    a2, a3, 116
600008cb:    0020c0           memw
600008ce:    1e6322           s32i    a2, a3, 120
600008d1:    0020c0           memw
600008d4:    1f6322           s32i    a2, a3, 124
600008d7:    0020c0           memw
600008da:    f00d         ret.n
С отключенным memw:
Код:
60000874 <write_test>:
60000874:    ff4d31           l32r    a3, 600005a8 <_stext+0x44>
60000877:    106322           s32i    a2, a3, 64
6000087a:    116322           s32i    a2, a3, 68
6000087d:    126322           s32i    a2, a3, 72
60000880:    136322           s32i    a2, a3, 76
60000883:    146322           s32i    a2, a3, 80
60000886:    156322           s32i    a2, a3, 84
60000889:    166322           s32i    a2, a3, 88
6000088c:    176322           s32i    a2, a3, 92
6000088f:    186322           s32i    a2, a3, 96
60000892:    196322           s32i    a2, a3, 100
60000895:    1a6322           s32i    a2, a3, 104
60000898:    1b6322           s32i    a2, a3, 108
6000089b:    1c6322           s32i    a2, a3, 112
6000089e:    1d6322           s32i    a2, a3, 116
600008a1:    1e6322           s32i    a2, a3, 120
600008a4:    1f6322           s32i    a2, a3, 124
600008a7:    0020c0           memw
600008aa:    f00d         ret.n
UDK (c отключенным memw):
Код:
40100000 <_stext>:
40100000:    000240           excw
40100003:    024460           excw
40100006:    486000           excw
40100009:    600002           l8ui    a0, a0, 96
4010000c:    024c         movi.n    a2, 64
4010000e:    506000           witlb    a0, a0
40100011:    600002           l8ui    a0, a0, 96
40100014:    000254           excw
40100017:    025860           excw
4010001a:    5c6000           excw
4010001d:    600002           l8ui    a0, a0, 96
40100020:    000260           excw
40100023:    026460           excw
40100026:    686000           excw
40100029:    600002           l8ui    a0, a0, 96
4010002c:    026c         movi.n    a2, -32
4010002e:    706000           excw
40100031:    600002           l8ui    a0, a0, 96
40100034:    000274           excw
40100037:    027860           excw
4010003a:    7c6000           excw
4010003d:    600002           l8ui    a0, a0, 96

40100040 <write_test>:
40100040:    fff031           l32r    a3, 40100000 <_stext>
40100043:    0329         s32i.n    a2, a3, 0
40100045:    ffef31           l32r    a3, 40100004 <_stext+0x4>
40100048:    0329         s32i.n    a2, a3, 0
4010004a:    ffef31           l32r    a3, 40100008 <_stext+0x8>
4010004d:    0329         s32i.n    a2, a3, 0
4010004f:    ffef31           l32r    a3, 4010000c <_stext+0xc>
40100052:    0329         s32i.n    a2, a3, 0
40100054:    ffef31           l32r    a3, 40100010 <_stext+0x10>
40100057:    0329         s32i.n    a2, a3, 0
40100059:    ffee31           l32r    a3, 40100014 <_stext+0x14>
4010005c:    0329         s32i.n    a2, a3, 0
4010005e:    ffee31           l32r    a3, 40100018 <_stext+0x18>
40100061:    0329         s32i.n    a2, a3, 0
40100063:    ffee31           l32r    a3, 4010001c <_stext+0x1c>
40100066:    0329         s32i.n    a2, a3, 0
40100068:    ffee31           l32r    a3, 40100020 <_stext+0x20>
4010006b:    0329         s32i.n    a2, a3, 0
4010006d:    ffed31           l32r    a3, 40100024 <_stext+0x24>
40100070:    0329         s32i.n    a2, a3, 0
40100072:    ffed31           l32r    a3, 40100028 <_stext+0x28>
40100075:    0329         s32i.n    a2, a3, 0
40100077:    ffed31           l32r    a3, 4010002c <_stext+0x2c>
4010007a:    0329         s32i.n    a2, a3, 0
4010007c:    ffed31           l32r    a3, 40100030 <_stext+0x30>
4010007f:    0329         s32i.n    a2, a3, 0
40100081:    ffec31           l32r    a3, 40100034 <_stext+0x34>
40100084:    0329         s32i.n    a2, a3, 0
40100086:    ffec31           l32r    a3, 40100038 <_stext+0x38>
40100089:    0329         s32i.n    a2, a3, 0
4010008b:    ffec31           l32r    a3, 4010003c <_stext+0x3c>
4010008e:    0329         s32i.n    a2, a3, 0
40100090:    0020c0           memw
40100093:    f00d         ret.n
И то что он наплодил в _stext констант - они не объединяются, т.к. каждая эксклюзивная. А у xtensa компилятора, при использовании базовых адресов со смещением константы объединяются для разных процедур. Даже если найдет константу, которая лежит в диапазоне использования регистра со смещением, то и её возьмет, а поправит смещение при обращении. Как итог - в UDK потеря не 9 байт, а более, на каждое обращение к регистру (к примеру в сравнении с xtensa).
Аналогично и при обращении к полям структур. Он будет выеживаться - прибавлять, вычитать из адресного регистра, но потом только по нулевому смещению возьмет данные. Ужас просто - плодит кучу команд вместо 3-х байтной обращения по регистру со смешением.... Кто-то спецом навредничал, чтобы не использовали бесплатный GCC и распространяет такой кривой компиллер... Внешними опциями это не удалось исправить. В xtensa можно и так и сяк крутить директивами в опциях компилятору...
Вполне серьезная причина выкинуть кривой UDK компилятор.
 
Последнее редактирование:
Сверху Снизу