Встала передо мной такая вот проблема — надо передавать данные между двумя микроконтроллерами STM32F407 хотя бы на скорости 100 Mbps. Можно было бы использовать Ethernet (MAC-to-MAC), но вот беда — он занят, именно из него и берутся эти данные…
Из незадействованной периферии есть разве что SPI — но он только 42 Mbps.

Как ни странно, ничего готового в сети не нашлось. И я решил реализовать параллельный тактируемый регистр на 8 бит. А что — частоту можно задать в 10 Мгц (то есть, конечно, собственно такты вдвое быстрее, но и 20 Мгц не есть что-то сложное) — так что с такой невысокой частотой не придется мучиться с разводкой платы. А скорость как раз и будет 100 Mbps.

Сказано — сделано. В общем виде система выглядит так. На передающей стороне используем таймер, один из сигналов сравнения выводим на пин — это будет тактовый сигнал, а второй будем использовать для запуска одной пересылки (burst) для DMA.

Шина у меня на частоте 82 МГц (из-за потребления тока на большей частоте :), таймер на той же частоте: так что при периоде ARR = 8 получается 10 Мгц примерно (стало быть будет около 80 Mbps, ну да и ладно).

DMA будет по такту пересылать один байт из памяти (с автоинкрементом, конечно) прямо в порт вывода регистра — в моем случае подошел PORTE — его первые 8 бит как раз и подходят как адрес приемника DMA.

На приемной стороне тактовый сигнал будем по обоим перепадам использовать для тактирования таймера, с периодом 1, а сигнал update будем использовать для запуска пересылки для DMA, который читает данные из порта (опять подошел порт PORTE) и записывает в память с автоинкрементом.

Теперь осталось правильно настроить все (код ниже) и запустить. Завершение на обеих сторонах определяется по прерыванию от DMA.

Однако, для полноты картины нужно конечно включить в код проверки на задержки передачи и обработку ошибок, но это я опускаю.

В коде ниже у таймера TIM8 использован канал CC2 для вывода сигнала — чтобы посмотреть, что получается.

volatile int transmit_done;
volatile int receive_done;

void DMA2_Stream1_IRQHandler(void) {
    TIM8->CR1 &= ~TIM_CR1_CEN;
    DMA2->LIFCR |= 0b1111 << 8;
    receive_done = 1;
}

void DMA2_Stream4_IRQHandler(void) {
    TIM1->CR1 &= ~TIM_CR1_CEN;
    TIM1->EGR |= TIM_EGR_BG;
    DMA2->HIFCR |= 0b1111101;
    transmit_done = 1;
}

void ii_receive(uint8_t *data, int len) {
    GPIOE->MODER = (GPIOE->MODER & 0xFFFF0000) | 0x0000;
    DMA2_Stream1->PAR = (uint32_t) &(GPIOE->IDR);
    DMA2_Stream1->M0AR = (uint32_t) data;
    DMA2_Stream1->NDTR = len;
    TIM8->CNT = 0;
    TIM8->BDTR |= TIM_BDTR_MOE;
    receive_done = 0;
    DMA2_Stream1->CR |= DMA_SxCR_EN;
    TIM8->CR1 |= TIM_CR1_CEN;
}

void ii_transmit(uint8_t *data, int len) {
    GPIOE->MODER = (GPIOE->MODER & 0xFFFF0000) | 0x5555;
    DMA2_Stream4->PAR = (uint32_t) &(GPIOE->ODR);
    DMA2_Stream4->M0AR = (uint32_t) data;
    DMA2_Stream4->NDTR = len;
    TIM1->CNT = 6;
    transmit_done = 0;
    DMA2_Stream4->CR |= DMA_SxCR_EN;
    TIM1->SR |= TIM_SR_BIF;
    TIM1->BDTR |= TIM_BDTR_MOE;
    TIM1->CR1 |= TIM_CR1_CEN;
}

// tx: TIM1 CH4 on DMA2/stream4/channel6, CH1 on output clock in PE9
// rx: TIM8 CH2 on DMA2/stream3/channel7, CH1 on input clock in PC6
void ii_init() {
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOE_CLK_ENABLE();
    __HAL_RCC_TIM1_CLK_ENABLE();
    __HAL_RCC_TIM8_CLK_ENABLE();
    __HAL_RCC_TIM2_CLK_ENABLE();
    __HAL_RCC_DMA2_CLK_ENABLE();
    GPIOC->MODER |= (0b10 << GPIO_MODER_MODE6_Pos)
            | (0b10 << GPIO_MODER_MODE7_Pos);
    GPIOC->PUPDR |= (0b10 << GPIO_PUPDR_PUPD7_Pos);
    GPIOC->AFR[0] |= (GPIO_AF3_TIM8 << 24) | (GPIO_AF3_TIM8 << 28);
    GPIOE->MODER |= (0b10 << GPIO_MODER_MODE9_Pos);
    GPIOE->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9 | 0xFFFF;
    GPIOE->AFR[1] |= GPIO_AF1_TIM1 << 4;
    GPIOE->PUPDR |= (0b10 << GPIO_PUPDR_PUPD9_Pos);
    TIM1->ARR = 8;
    TIM1->CCR1 = 5;
    TIM1->CCR4 = 1;
    TIM1->EGR |= TIM_EGR_CC4G;
    TIM1->DIER |= TIM_DIER_CC4DE;
    TIM1->CCMR1 |= (0b110 << TIM_CCMR1_OC1M_Pos);
    TIM1->CCER |= TIM_CCER_CC1E;
    TIM1->EGR |= TIM_EGR_BG;
    TIM8->ARR = 1;
    TIM8->CCR2 = 1;
    TIM8->EGR |= TIM_EGR_UG;
    TIM8->DIER |= TIM_DIER_UDE;
    TIM8->SMCR |= (0b100 << TIM_SMCR_TS_Pos) | (0b111 << TIM_SMCR_SMS_Pos);
    TIM8->CCMR1 = (0b01 << TIM_CCMR1_CC1S_Pos) | (0b110 << TIM_CCMR1_OC2M_Pos);
    TIM8->CCER |= (0b11 << TIM_CCER_CC1P_Pos) | TIM_CCER_CC2E;
    DMA2_Stream1->CR = DMA_CHANNEL_7 | DMA_PRIORITY_VERY_HIGH | DMA_MINC_ENABLE
            | (0b00 << DMA_SxCR_DIR_Pos) | DMA_SxCR_TCIE | DMA_SxCR_TEIE
            | DMA_SxCR_DMEIE;
    DMA2_Stream1->FCR |= DMA_FIFOMODE_ENABLE;
    DMA2_Stream4->CR = DMA_CHANNEL_6 | DMA_PRIORITY_VERY_HIGH | DMA_MINC_ENABLE
            | (0b01 << DMA_SxCR_DIR_Pos) | DMA_SxCR_TCIE | DMA_SxCR_TEIE
            | DMA_SxCR_DMEIE;
    DMA2_Stream4->FCR |= DMA_FIFOMODE_ENABLE;
    HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
    HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);
}

Для тестов была использована одна и та же плата, просто тактовый выход PE9 был соединен с входом PC6. Главный цикл выглядел так:

 ii_receive(rdata, 256);
 ii_transmit(tdata, 256);
 while (!transmit_done);
 while (!receive_done);

По результатам: данные отлично пересылались за 30-31 микросекунду без потерь. Сигналы выглядят как-то так:


здесь белый — выход таймера TIM8, красный — тактовый сигнал (TIM1), ну а оранжевый — это младший бит данных (0-1-0-1-...).

Что не нравится при этом — ну нельзя никак запускать DMA от прерывания от входа GPIO, вот и приходится работать с таймерами. Может, кто-нибудь подскажет другой способ?

P.S. В результате свежих экспериментов выяснилось, что поднятие частоты до 168 МГц закономерно увеличило скорость в 2 раза и данные передались за 14 мксек ( то есть 150 Mbps), а вот при уменьшении границы мастер-таймера ниже 7 начались глюки приемной стороны — не успевает таймер TIM8. При 7 еще работает, но при 6 — уже нет, а ведь это 200 Mbps было бы…

Комментарии (83)


  1. besitzeruf
    21.07.2019 10:06

    Нк раз такой велосипед изобрелся, то спрошу: не проще ли будет использовать 2+ SPI на максимальной скорости (один для первой половины, второй для второй половины данных)? Пинов отнимите в идеале 6 и еще прием организовать сможете.


    1. oam2oam Автор
      21.07.2019 10:19

      Я так и попробовал вначале — но вот незадача, я могу только SPI1 и SPI3 использовать, тут, во-первых SPI3 только 24 Mbps дает, да и то при 168 МГц, ну и во-вторых, разводка все-же усложняется. А вот пинов хватает, аж остается… Так что такой подход вполне себе жизнеспособен, я думаю. К тому же остается запас по скорости — тут можно и поднять ее хотя бы в 2 раза…


  1. Griboks
    21.07.2019 10:11

    «Можно было бы использовать Ethernet (MAC-to-MAC), но вот беда — он занят, именно из него и берутся эти данные…»
    А он разве симплексный? Сетевой адаптер разве не может одновременно передавать и получать данные? А данные не могут идти сразу на нужное устройство?


    1. oam2oam Автор
      21.07.2019 10:26
      +1

      Ethernet конечно, дуплекс. Но тут требуется получить пакет из Phy и его обработать, а затем передать на другой контроллер (идет борьба за стоимость :)


      1. nevzorofff
        21.07.2019 22:38

        А при вашем способе передачи его «обработать» не надо?


        1. oam2oam Автор
          22.07.2019 07:32

          не понял ваш вопрос. Я и написал, что надо обработать, а сетевой адаптер просто передаст данные.


          1. nevzorofff
            22.07.2019 21:27

            Ну на FD интерфейсе ничто не мешает данные принять, обработать и отдать, лишь бы проц «обработку» потянул.


            1. oam2oam Автор
              23.07.2019 08:33

              а что это — FD интерфейс и где он?


              1. nevzorofff
                23.07.2019 17:54
                -1

                Режим Full Duplex у Ethernet, позволяет одновременно данные и принимать и отправлять.


                1. oam2oam Автор
                  23.07.2019 18:01

                  У микроконтроллера нет никакого FD, а есть MAC, все пляски тут и происходят — MAC принимает данные, использует выделенный DMA, записывает их в цепочку блоков данных и затем устанавливает прерывание. То же и для отправки (в обратном порядке) надо сделать. Ну а в промежутке обработать пакет (собрать из кусков, проанализировать...). В статье же решалась проблема, когда пакет принят на одном MAC, а передать его надо на другом MAC — одно из решений использовать второй MCU (так как MAC один на контроллер, два очень редко и дорого). Есть еще другие решения — использовать внешний MAC (тут много способов).
                  Ну вот, а ниже MAC лежит PHY, вот у него-то и есть FD — но это совершенно все равно и не интересует, поскольку никак не сказывается на задаче…


                  1. nevzorofff
                    23.07.2019 20:02
                    -1

                    Задача стояла другая принять и отправить данные на скорости 100мбит/с:

                    Встала передо мной такая вот проблема — надо передавать данные между двумя микроконтроллерами STM32F407 хотя бы на скорости 100 Mbps. Можно было бы использовать Ethernet (MAC-to-MAC), но вот беда — он занят, именно из него и берутся эти данные…


                    Ethernet интерфейс с этим справляется.
                    Но вы, зачем-то, решили принимать по Ethernet, а отправлять собственно изобретённым велосипедом.


  1. evgeniy1294
    21.07.2019 10:27
    +6

    Для скоростной передачи данных есть контроллеры c quad/octo-spi, необходимость которых определяется на этапе проектирования.
    Параллельный порт называется параллельным, потому что его можно использовать, внезапно, как параллельный. Вот только прерываний и флагов, необходимых для работы с данными у него обычно нет, соответственно и контроллер DMA с ним работать не сможет.
    Поэтому для реализации скоростных интерфейсов, например для связи с FPGA, и используются OCTO/QUAD SPI, позволяющие реализовать пропускную способность выше 100 мбит/с.


    1. oam2oam Автор
      21.07.2019 10:28

      Вот может подскажете микроконтроллер stm32 c OCTO/QUAD SPI? Я вот думал использовать stm32H750VB…


      1. evgeniy1294
        21.07.2019 10:35
        +2

        C quad-spi все просто, линейки stm32f46x/47x и линейки stm32f7/h7. С octo-spi сложнее (линейка на ядре L4+), у ST пока нет чипов с OSPI и ETH на одном кристалле, обещали сделать. QUAD-SPI должно быть достаточно.
        Кстати, в CoubMX есть удобный фильтр для подбора чипов.


        1. oam2oam Автор
          21.07.2019 10:41

          Но как использовать QuadSpi для пересылки между контроллерами? Он ведь предназначен для работы с flash-памятью. Положим, нам надо отправить с mcu1 на mcu2 данные. Мы формируем пакет данных на mcu1 (ну пусть там добавятся адреса и т.д.). А что делать на стороне mcu2? Я вот как-то не соображу, как там быть — туда же придут данные как на flash, а он и не умеет с ними работать?


          1. evgeniy1294
            21.07.2019 10:47
            +1

            Все очень просто, думайте о QSPI как об обычном spi с 4-мя параллельными шинами данных.


            1. oam2oam Автор
              21.07.2019 10:53

              Не выходит — вот например в даташите на stm32h750vb написано:
              The QUADSPI communicates with the Flash memory using commands. Each command
              can include 5 phases: instruction, address, alternate byte, dummy, data. Any of these
              phases can be configured to be skipped, but at least one of the instruction, address,
              alternate byte, or data phase must be present.
              То есть, я так понимаю, если отключить все ненужные фазы (ну например instruction, address, alternate byte) и ожидать приема данных, то что придет будет dummy+data — в непрерывном режиме данных наверно и можно принять…
              Попробую (как раз есть stm32h750vb)… Но вот я тут подумал, что если для описанного в статье способа поднять частоту шины в 2 раза и уменьшить таймер до 2, то на 8 линиях данных мы получим… 800 Mbps, причем на том же железе за те же деньги, а если еще найти порт с 16 свободными пинами… И зачем тогда QuadSPI :)


              1. evgeniy1294
                21.07.2019 11:02

                Вы в статье размышляли об использовании eth для решения задачи, неужели отбросить лишний заголовок кадра для вас такая большая проблема?))
                Конечно, вы можете есть кактус, если хотите.


                1. oam2oam Автор
                  21.07.2019 11:04

                  Я вот ниже написал, ну не понимаю как на стороне slave это использовать? Не отключается же clock — он только на выход! (ну в stm32h750)


            1. oam2oam Автор
              21.07.2019 10:57
              +1

              И все равно не понимаю — у QuadSPI нет режима slave. Как он данные-то принимать будет? Он же в режиме чтения сначала пишет на линию, а затем читает… а как это синхронизировать с мастером? Мастер же тоже как-раз пишет на линию…
              И кто будет тактовый сигнал генерировать?


          1. besitzeruf
            21.07.2019 12:22

            разве что использовать indirect read/write моды (но не уверен, так как не имел еще опыта с QUAD SPI интерфейсом).


            1. oam2oam Автор
              21.07.2019 12:42

              неполучается — смотри мой коммент ниже


    1. oam2oam Автор
      21.07.2019 11:10

      В общем, проведенные тесты для stm32h750vb показали, что в режиме чтения QuadSPI гонит на выход тактовый сигнал, посылает адрес и пустой байт и затем читает данные. Никаким способом реализовать режим slave не удалось. Видимо, и остальные stm32 будут вести себя также… печаль…


      1. evgeniy1294
        21.07.2019 11:30
        +1

        Мастером будет приёмный контроллер, слейв получается программный, да. У меня не было проблем со слейвом, так как в качестве него выступала FPGA, для которой было написано соответствующее ip-ядро.
        Вообще у вас интересная задача. Вы получаете данные по eth, но, похоже, не имеете возможности обработать их на этом же камне. Поэтому пересылаете все в следующий МК. У вас данные требуют специфической обработки? Или просто скорости не хватает? Или одна из железок готова и нужно «расширить» её возможности?


        1. oam2oam Автор
          21.07.2019 11:52

          Да, тут такая история — сначала был stm32f107 и он работал с двумя портами eth (по очереди) и реализовывал что-то типа прозрачной сетевой оболочки для конечного устройства (добавляя функционал)… но наступил этап роста и один камень сейчас я заменяю на два (по phy на mac), вот и потребовалась связь между ними (все же там 10/100 Mbps, ну в одну сторону поменьше все же).
          ну и функционал растет и надо бы на один тип микроконтроллеров перейти (чувствую это все же будет stm32h750 — в одном месте мне надо сильно много вычислять...) для экономии. Ну и цену на все это бы понизить как-то…
          Не могу пока придумать решение дешевле 2000 рублей — такой вот двухпортовый хаб с возможностью контроля всех пакетов…


          1. Kitsok
            21.07.2019 12:55

            Может быть посмотреть в сторону сетевых SoC вроде тех, что используют производители SOHO-роутеров?


            1. oam2oam Автор
              21.07.2019 13:00

              Тут ведь какое дело — есть куча чипов 2 порта+ 1 порт на контроллер… и вроде бы недорогие. Но! это уже готовые роутеры vlan и никак не сделаешь фильтрацию и обработку (с подменой и синтезом) пакетов… А все остальное — ну есть вроде микроконтроллеры с ДВУМЯ MAC — но цена… заоблачная…


          1. Ivanii
            21.07.2019 12:57

            www.oldi.ru/catalog/element/0519569 не пойдет в качестве железа или сразу с ОС?


            1. oam2oam Автор
              21.07.2019 13:01

              вот как раз с ОС и не надо… это устройство еще и много чего должно делать — например по CAN общатся. И стартует оно 100 миллисекунд (ибо промышленное)


          1. evgeniy1294
            21.07.2019 12:59
            +1

            У микроконтроллеров dual ethernet не встречал. Ближайшее подобное есть у nuvoton — NUC980, чипы позиционируются для IoT, стоят в районе 5-7$ в партиях от 1000 шт, контрактная цена должна быть немного ниже.
            Но это уже MPU, со всеми вытекающими.


            1. oam2oam Автор
              21.07.2019 13:02

              ну вот да… так-то переходить без особой причины c Cortex-M не нужно :) Тут много причин…


            1. predator86
              21.07.2019 17:20
              +2

              NXP такие делает.


              1. oam2oam Автор
                21.07.2019 17:22

                Да, у меня даже лежат штук 10 50-х… вещь как-бы хорошая, но цена негуманная, и программировать его очень сложно — чего стоит только процедура загрузки… Но два eth — это два eth. В общем — из-за цены непрошло.


            1. semen-pro
              22.07.2019 16:34

              Можно взять Raspberry Pi, его можно запустить без Ос, как микроконтроллер. Где-то видел примеры.

              UPD: сорри, сморозил глупость, вспомнил что там только 1 порт, а у аналогов бывает несколько. Главное, выкинуть Ос, например, OpenWrt и писать на голом железе.


              1. Dima_Sharihin
                22.07.2019 16:44

                Вот только у малины нет двух Ethernet'ов


  1. SadAngel
    21.07.2019 13:20

    "Что не нравится при этом — ну нельзя никак запускать DMA от прерывания от входа GPIO, вот и приходится работать с таймерами. Может, кто-нибудь подскажет другой способ?"


    На Cypress PSoC так получиться. И QSPI тоже есть, но нет ethernet (есть только MDIO (


    1. oam2oam Автор
      21.07.2019 14:27

      Как выяснилось — qspi не катит :(
      Ну и главное — без eth нет смысла…


  1. Sdima1357
    21.07.2019 13:51

    Может посадить второй контроллер на клок от первого (mc01->BYPASS clock source) — принудительная синхронизация и попробовать читать дату с порта синхронно?
    И кстати — на 100 Мb сеть я бы не расчитывал. В лучшем случае на 50-70.


    1. oam2oam Автор
      21.07.2019 14:26

      ничего не выйдет — нужен именно механизм синхронного таймера — ну вот как в SPI, иначе никак не определить посылку — нужен сдвиг примерно в 0.5 такта.
      А сеть да — обычно 40-60 Mbps. Ну так это еще и дуплекс, так что 80 должно хватить :)


  1. Inanity
    21.07.2019 14:39
    +3

    Ещё пару вариантов разной степени упоротости:

    1. У STM32F407, насколько я понял из документации, бортовой USB не умеет HS, только FS. Зато у него есть интерфейс ULPI, который позволяет подключить внешний USB2.0 PHY. Я когда-то работал с ULPI. Конечно на этом камне ULPI интерфейсы воткнуть друг в друга не получится, как бы это красиво не выглядело, т.к. в ULPI именно PHY задаёт flow control, управляя ногами DIR и NEXT. С другой стороны сами эти PHY достаточно простые и дешёвые, они стоят менее 1.5$ (USB3300, например). Взять 2 PHY на каждый камень, соединить их друг с другом по USB и получить что-то около 480mbit/s. Теоретически даже не нужно будет поддерживать целиком интерфейс USB, т.е. дескрипторы и прочие пляски, т.е. сразу сырые данные кидать туда-сюда, но это нужно проверять. Тут и все прелести DMA можно будет использовать из коробки. С разводкой особых проблем быть не должно, ULPI это 12 ног на частоте 60Mhz и PHY друг с другом дифф.парой соединить.

    2. Использовать staic memory controller. C помощью него STM32F407 умеет цеплять внешнюю память. Тут вариантов много.
    a). Самый тупой способ. Берём микросхему двухпортовой SRAM памяти и цепляем на два проца. Двухпортовая память дороже обычной, но можно сэкономить на объёме, т.к. передача скорее всего планируется пакетная. Какая-нибудь ущербная 8-битная двухпортовая SRAM с доступом в 55ns даст что-то около 145mbit/s. По деньгам <9$ (71V30S, например), но можно искать ещё.
    b). Если не хочется иметь дело с dual-port, то чисто теоретически можно одну SRAM память прицепить на 2 контроллера, если есть возможность делать нормальный tristate на управляющем порту проца. Это требует исследования. Зато память можно взять по-шустрее, шину по-больше и компенсировать тем самым все задержки переключения памяти от проца к процу. Единственное, с синхронизацией процесса передачи будет морока.
    c). Что-то мне подсказывает, что теоретически к этому контроллеру можно подцепить даже аппаратное cmos asynchronous FIFO. Микросхемы малого объёма и скорости достаточно дёшевы <7$ (7201LA15JG, например).
    d). Совсем обнаглеть и соединить два проца через эту шину напрямую. Это требует досконального понимания работы этого контроллера и его режимов. Но т.к. он умеет работать с NAND, который имеет флаг READY/BUSY, то теоретически возможность для flow control имеется и можно из проца в проц с помощью DMA гнать данные. Но это нужно крайне тщательно проверять.


    1. oam2oam Автор
      21.07.2019 14:49

      Ну все варианты, кроме 2d :) — удорожание, так-то провода ведь бесплатны :).
      А вот над 2d я думал (недолго, правда) — но так и не понял, как делать…
      Есть и еще ньюансы — скорость будет со всеми фазами и их таймингами немного меньше (примерно до 42 Mbps), а вот пинов сожрет… 24+16+12 — ой-ой, вот столько у меня точно нет.
      И главное — это всё конфликтует за пины с eth, а те неизменяемы…
      Вообще у stm-ок очень не хватает мультиплексора линий все-на-все.


      1. Sun-ami
        21.07.2019 16:13

        А что так много пинов для варианта 2d насчитали — адрес ведь там совсем не нужен? Да и шину данных можно попробовать 8-битной сделать, и шина управления — не 12 пин.


        1. oam2oam Автор
          21.07.2019 16:16

          ну от адреса да — можно избавиться, но управление явно больше 6


  1. Sap_ru
    21.07.2019 16:15

    1) Можно подцепить устройство, как внешнюю шину и для тактирования передачи использовать соответсвующие сигналы. DMA будет работать. Самый праивльный способ.
    2) Можно извартиться с таймерами и так же использовать DMA.


    1. oam2oam Автор
      21.07.2019 16:18

      можно поподробнее — как это как внешнюю шину? У stm32 нет никаких шин, к сожалению — в этом то все и дело!
      А с таймерами в статье и описано как…


  1. Firelander
    21.07.2019 16:18

    Делал что-то подобное для считывания данных с АЦП. Кстати, заметил, что с некоторыми таймерами не завелось, моё предположение что GPIO и таймер должны сидеть на той же шине.


    1. oam2oam Автор
      21.07.2019 16:28

      Но ведь таймеры (AHB) и порты (AHB1) всегда на разных шинах? У меня заводиться всегда, но при малых значениях ARR идет пропуск данных DMA — они повторяются сериями…


      1. Firelander
        21.07.2019 16:39

        Да, посмотрел, шины разные. Может в чем-то другом косяк был, просто так в памяти отложилось, давно делал.


  1. hardegor
    21.07.2019 19:48

    Что не нравится при этом — ну нельзя никак запускать DMA от прерывания от входа GPIO, вот и приходится работать с таймерами. Может, кто-нибудь подскажет другой способ?

    Таймер дергать через ETR/Capture, а уже таймер будет запускать DMA.
    А еще в H7 видел дополнительный слой управления DMA — DMAMUX2 и там есть триггеры EXTI0 и EXTI1.


    1. oam2oam Автор
      21.07.2019 21:15

      Именно так и сделано. А вот насчет H7 я уже и сам думаю — по цене не сильно дороже выходит, только вот по току — надо проверить…


  1. SadAngel
    21.07.2019 21:11

    А MCU 2-ма ядрами не рассматриваете?


    1. oam2oam Автор
      21.07.2019 21:14

      так мне надо два eth, а не два ядра. А таких очень мало и они очень дорогие…


  1. AVI-crak
    21.07.2019 21:23

    Мне кажется что два слабеньких камня + обвязка — стоят дороже одного, но более шустрого.


  1. Fox_Alex
    21.07.2019 22:30

    А редактировать надо и входящие и выходящие из девайса пакеты? Если только одну сторону — то можно одним езернетом обойтись. RX в линию, а TX в девайс.

    Или можно вообще разделить контроль: один проц как написано выше, а второй так-же, только в обратную сторону. Тогда возможно траффик между процами можно будет сильно сократить.


    1. oam2oam Автор
      21.07.2019 22:36

      в одну сторону, конечно, не получится… но что-то в этом есть!


  1. IgorPie
    22.07.2019 00:05
    +1

    Хм, ну в пределах одного МК фаза не разъезжается и все работает. А дальше? а когда индуктивность земли постучится в дверь?


    1. oam2oam Автор
      22.07.2019 07:35
      +1

      Проверил на двух платах, соединенных проводками (вообще ужас и лапша) — все нормально. И вообще, я конечно следую всегда высокому искусству черной магии, но перебарщивать тоже не надо — когда у вас 10 Мгц и триггера Шмидта везде где только можно и нельзя — можно немного расслабится и получить удовольствие :)


      1. IgorPie
        22.07.2019 17:16

        Теоретически, возможен случай, когда фазы МК №1 и №2 разъедутся на 180 градусов? «Оверсемплинга» на реакцию совсем не остается, если тактовая 168МГц, а порты на 100МГц.
        А разъехаться она может через несколько часов, или может, дней.
        Имхо.


        1. oam2oam Автор
          22.07.2019 17:22

          нет, это невозможно — надеюсь, я смог донести, что фазы отсчитываются каждый раз при новом выходном такте — а это 8 тактов TIM1 — то есть фазы разъедутся на 1/80 мксек максимум (60 градусов), а выборка происходит за 1/10 мксек (180 градусов). Другое дело, если DMA не дадут времени для считывания или записывания порта — тут, конечно, беда будет…


          1. IgorPie
            22.07.2019 19:55

            такты — тактами, но все синхронизируется от кварцев, PLL и далее по тексту. И если тактовые двух МК после делителей разъедутся в противофазу? Механизма состройки — нету, же.
            Понимаю, что притянуто за уши, но палки стреляют, когда не ждешь


            1. oam2oam Автор
              22.07.2019 20:33

              да нет, вы не так поняли систему — такты с выхода первого МК идут на вход таймера второго — так что разница не может превышать одного такта шины второго — а это 82 МГц… при тактах в 10 МГц


              1. IgorPie
                22.07.2019 21:07

                ну вот клок второго будет сдвинут и защелкнется на 1 такт позже (или раньше), т.е. может быть ситуация, что первый МК выдаст 8+8 бит, а второй защелкнет их как 9+7+случайный бит


                1. oam2oam Автор
                  22.07.2019 21:11
                  +1

                  не-не… расстояние между моментами сэмплирования 8 тактов, так что смещение до 3 тактов — ни на что не влияет, а оно не может быть больше 1 такта (даже в противофазе). Гораздо важнее то, что после сэмплирования DMA не сможет взять данные — для этого и есть задержка до 2 тактов.


  1. Dima_Sharihin
    22.07.2019 11:47

    А почему нельзя просто взять внешний аппаратный MAC-контроллер? К примеру LAN9250


    1. oam2oam Автор
      22.07.2019 12:57

      Можно и так, но:
      1. Цена сильно увеличивается — сравните LAN9250 — 500-600 рублей, а ksz8081 — 50-60 рублей, а их два…
      2. Та же проблема — как с ним работать? у него SPI & QSPI — в первом случае 42 Mbps, а второй случай — по скорости вроде годится, но у не у всех stm есть.
      А так да, хорошее решение… но дорогое


      1. Dima_Sharihin
        22.07.2019 13:05

        Не сравнивайте теплое с мягким. LAN9250 избавляет от необходимости ставить второй МК и городить весь этот кошмарный огород, так что сравнение цен некорректное.


        не у всех stm есть.

        Вы микроконтроллеры продвигаете или задачу решаете? МК выбирается под задачу, а не наоборот, выбирайте то, что решит вам задачу, а не создаст еще две.
        Так может оказаться, что проще поставить какой-нибудь AMIC110 и сколотить микропрошивку на базе RTOS


        1. oam2oam Автор
          22.07.2019 13:12

          Вот смотрите — решение на базе даже двух МК стоит мне в производстве 2100 рублей (с корпусом, а уж на базе одного — и вовсе 1700), а то же на базе LAN9250 — уже 2800. Вы понимаете, это как с EROI — если я могу продать по 2500, то даже супер решение но дороже хоть на рубль — не годится от слова совсем.
          И с микроконтроллерами вы не правы — я потому и использую stm (и да, да, ещё и Cube!), что время разработки ПО для меня на новый камень менее дня — как бы требования не изменялись.
          Я уж и не знаю, МК выбирают под задачу видимо в стране розовых пони, а на практике — что есть, то и используем. И важно, чтобы стоимость перехода ПО была минимальна — желательно 0 ;)


          1. Dima_Sharihin
            22.07.2019 13:22

            Я что-то не очень улавливаю: сколько в вашей схеме стоит один микроконтроллер? Включая его программирование.
            По вашей арифметике MCU+PHY стоит 400 рублей. Что мало отличается от стоимости LAN9250, где в ход вступают просто договорные отношения, какую скидку под проект вы сможете выбить.


            (и да, да, ещё и Cube!)

            Ничего святого...


            1. oam2oam Автор
              22.07.2019 13:26

              так ведь принятые пакеты надо еще и обрабатывать, так что без MCU никак не обойтись. А устройство таково, что нужен MCU с довольно богатым внутренним миром набором периферии. MCU+2хPHY стоит мне 350 рублей. а MCU+2xLAN — будет 1100 (примерно). Вот эта разница в 750 рублей это порог, отделяющий то что можно сделать от того, что можно продать… Приходится делать то, что можно продать…


              1. Dima_Sharihin
                22.07.2019 13:33

                В топике стояла задача "добавить еще один MAC-уровень в существующую систему". Вот вы берете свой STM32F407, и вторым интерфейсом ставите к нему LAN9250. Да, у вас линии получатся разные, но где в тексте написано требование, что они должны быть идентичны? Вы городите что-то вроде пограничного маршрутизатора, изолирующего два сегмента сети, "реальные" 100 мегабит там возможно и не нужны


                1. oam2oam Автор
                  22.07.2019 13:38

                  Под влиянием нашего обсуждения я подумал, что можно же например KSZ8851M добавить вместо второго phy. Вот это уже даже удешевляет систему. А так у меня уже два MAC есть… система потребовала увеличения производительности (очень много математики) — и я сейчас перебираю решения.
                  Вот уже просматривается связка stm32h750+ksz8081+ksz8851M — а это всего 550-600 рублей, что очень здорово, если удастся сохранить 40-50 Mbps пропускной способности — надо проверять…


  1. Sun-ami
    22.07.2019 12:14

    В STM32F750 для передачи данных между микроконтроллерами можно использовать SAI. SAI может работать на частоте выше частоты ядра, к примеру ядро — на 84МГц, а SAI — на 96 или даже 120МГц. Ему нужно всего 4 пина. А если пины заняты, или нужно снизить частоту — в F750 есть ещё и второй SAI. CubeMX не позволяет задать частоту MCLK 84МГц или 120МГц, но регистры вроде бы позволяют, неясно только, будет ли слэйв работать при таком соотношении тактовой частоты SAI и внешнего MCLK.


    1. oam2oam Автор
      22.07.2019 12:59

      SAI — это последовательный интерфейс и он обычно объединен с SPI (с точки зрения сигналов это одно и то же — SCK + DATA). Так что лучше уж SPI — он и проще, можно сразу инициировать DMA и спокойно работать дальше. Но скорость SAI такая же — не выше 42 Mbps


      1. Sun-ami
        22.07.2019 13:34

        SAI тактируется от независимого PLL. Поэтому непонятно, откуда ограничение в 42 Mbps. И SAI тоже работает с DMA


        1. oam2oam Автор
          22.07.2019 13:45

          Вы понимаете, затактировать можно и от 256 МГц, но это значит, что у вас на пине будет SCK 256 МГц, что ну никак не может быть… На пине допустимо даже и 100 МГц, но стоимость разводки такой платы… я бы не взялся заставить работать такую шнягу…
          Реально можно допускать 40-50 МГц, с помощью черной магии это можно заставить работать в серии. У меня в статье — всего 10 МГц, и то был справедливый комментарий о сложности с фронтами.


          1. Sun-ami
            22.07.2019 13:51

            Для высоких частот всё зависит от длины линии. Если поставить контроллеры на расстоянии 5мм друг от друга, так, чтобы длина высокочастотных дорожек была 5..7 мм, и обеспечить неразрывный слой земли под ними с подключением к ближайшим выводам микроконтроллера — будет работать и на 120МГц. А если использовать 2 SAI — можно обойтись и 50 мегагерцами, тогда можно разнести микроконтроллеры и на 30 мм.


            1. oam2oam Автор
              22.07.2019 13:53

              Но тогда закономерный вопрос — а зачем SAI, если есть SPI (129 Mbps)? Это одно и то же на физическом уровне, но в обработке SPI гораздо лучше.


              1. Sun-ami
                22.07.2019 13:59

                Чтобы использовать индивидуальный PLL SAI, и не разгонять ядро и весь периферийный домен. Кроме того, частоту SAI можно выбирать с меньшим шагом.


      1. Sun-ami
        22.07.2019 13:55

        Посмотрел — действительно, оба SAI тактируются ещё и от клока домена APB2. Непонятно, где внутри SAI проходит разграничение APB2 и собственной синхронизации.


  1. Sun-ami
    22.07.2019 13:33

    -


  1. siargy
    24.07.2019 13:24

    P.S. В результате свежих экспериментов выяснилось, что поднятие частоты до 168 МГц закономерно увеличило скорость в 2 раза и данные передались за 14 мксек ( то есть 150 Mbps), а вот при уменьшении границы мастер-таймера ниже 7 начались глюки приемной стороны — не успевает таймер TIM8. При 7 еще работает, но при 6 — уже нет, а ведь это 200 Mbps было бы…

    а надо смотреть на форму сигнала осцилографом, чтобы понятно было что такое искажение сигнала в длинной линии.
    и 200Мгц на монтажке соплями это из области магии.


    1. oam2oam Автор
      24.07.2019 16:03

      Вы видимо невнимательно прочитали — 200 Mbps это 25 Мгц.


      1. siargy
        25.07.2019 11:34

        ну да, параллельная шина. кстати в пиках аппаратный паралельный порт есть