Перейти к содержанию
    

VladislavS

Свой
  • Постов

    1 239
  • Зарегистрирован

  • Посещение

  • Победитель дней

    9

Сообщения, опубликованные VladislavS


  1. Так нельзя из кварца 12 МГц получить 170. 

    Вход PLL должен быть больше 2.66 МГц , то есть 3, 4, 6 или 12 МГц. Частота PLL должна быть 96-344 МГц. 

    В этих ограничениях ближайшее что можно получить : 12/4*113/2= 169,5 МГц или более красивое 12/3*84/2 (12/2*56/2, 12*28/2) = 168 МГц.

  2. Достаём хрустальный шар.

    Приём UART через DMA путём опроса могу нафантазировать разными способами:

    1. Опрашиваем в главном цикле флаг RXNE. Если он вскочил, то запускаем DMA на передачу данных из DR в память. Ждём окончания передачи опять же опросом флагов DMA. Выключаем DMA. 

    2. Запускаем DMA на приём байта из DR. В основном цикле опрашиваем флаги DMA на предмет окончания приёма. Выключаем DMA.

    3. Можно ещё извращённых методов придумать с опросом флагов UART через DMA... 

    В сочетании с HAL на 2400-9600, пожалуй, взлетит. 🙂

    Убираем хрустальный шар.

  3. makefile это своего рода программа. Я бы вызывал make с параметром CONFIG=XXX и в зависимости от значения CONFIG формировал разные ключи компиляции и директорию куда компилировать.

  4. 6 часов назад, jcxz сказал:

    В таком же, в каком многоядерность имеет отношение к VTOR

    Много ядер - много VTOR-ов. Но я скорее обратил внимание на количество разных областей памяти. Одних только SRAM штук 8 насчитал. И флэшек штуки три. Ну и два ядра тоже не стимулируют шаблонный подход.

  5. 3 минуты назад, haker_fox сказал:

    Поэтому, первые два адреса таблицы (стэк и старт) всё равно есть.

    Это нужно только чтобы Cortex-M стартанул в железе без всяких загрузчиков. У других ядер другие условности. Если вы стартуете из-под загрузчика, то можете сделать как захочет ваша левая пятка. Другое дело, что особого смысла переделывать этот механизм нет, только себя путать.

  6. 34 минуты назад, Arlleex сказал:

    А разве это удобно?

    Зачем бедному загрузчику знать есть у вас VTOR или нет у вас VTOR, пользуетесь вы начальной таблицей векторов или формируете её в SRAM, делает приложение ремап или нет?

    34 минуты назад, Arlleex сказал:

    поэтому изначально VTOR даже не трогают

    Представьте ситуацию, что нет никакого загрузчика. Ваше приложение (пусть это будет Cortex-M) стартануло с 0x0800'0000 со значением VTOR=0. Разве это оптимальная конфигурация?

  7. Да нет никакой галки. IAR-у вообще по барабану с какого адреса грузить. Что в icf и соответственно в elf написано, туда и грузит. Оттуда же и запускает. Думаете ему есть разница с 0x0800'0000, 0x0801'0000 или 0x2000'0000 грузить?

  8. IAR достаточно умный, чтобы при старте отладки кортексов установить стек и передать управление на ResetHandler самостоятельно на основе icf. Единственное, что должна прошивка сделать самостоятельно, это установить VTOR или сделать ремап, где это надо. Лучше это делать не в загрузчике, а в основной прошивке, потому что прошивка с таблицей векторов может поступать совершенно непредсказуемо. 

    extern void(*__vector_table[])();
    SCB->VTOR = (uint32_t)&__vector_table;

    Этот простой код позволяет отлаживать код в какой угодно области памяти, хоть в SRAM. Просто переписав icf.

    Если нет VTOR,  то там ремап есть. Для отладки в SRAM под условной компиляцией ремап делаю

    #ifdef __DEBUG_SRAM__
    // REMAP SRAM -> 0x00000000
    SYSCFG->CFGR1 = _VAL2FLD(SYSCFG_CFGR1_MEM_MODE,3); 
    #endif

    При отладке чем-то менее умным ставлю в стартапе установку стека на основе скрипта линкера

    extern void* __reserved_for_stack_end__;
    __set_MSP((uint32_t)&__reserved_for_stack_end__);

     

    • Thanks 1
  9. 13 часов назад, Xenia сказал:

    Ну, а что произойдет на линии, если я раньше срока запишу единичку в EGR? Инвертируется ли в этот момент сигнал на выходном пине или нет?

    Состояние выхода зависит от значения счётчика на входе компаратора и режима работы, всё. Меняется состояние счётчика по счёту или каким-то внешним воздействием - компаратору по барабану.

  10. 7 часов назад, Mark16 сказал:

    Пытаюсь этот исходник на stm32 перенести .

    Не вижу тут требование отсутствия Autoend. Количество данных заранее известно. В моей функции просто заменяете отправку из буфера base()->TXDR = *data++; на отправку сначала одной константы I2C1->TXDR = SSD1306_DATA;, а потом в цикле I2C1->TXDR = fill;.

    И вообще, подобные вещи с DMA делают. Но это можно следующим шагом переделать после того как просто заработает. Ну и осциллоглядом контролировать обязательно.

     

    23 минуты назад, AlanDrakes сказал:

    Заточено под F401 (но I2C периферия в L05x не особенно отличается - проверил по референсу).

    При всём уважении, но у F401 реализация I2C старая как у F103 скорее. У L051 новая как в моих функциях.

     

    Спойлер

    image.thumb.png.7a32a16f37f28e7335d06397adc081e4.png

     

     

  11. Только ограничение YYYY на 255 немного портит малину. Если данных мало, то всё просто

    Спойлер

     

    bool MasterWrite(const uint8_t hw_adr, uint8_t *data, uint8_t len)
    {
      base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,len) | hw_adr | I2C_CR2_AUTOEND | I2C_CR2_START;
      while(len--)
      {
        if(!waitISRBitSet<I2C_ISR_TXIS>()) return false;
        base()->TXDR = *data++;
      }    
      return true;
    }
    
    // Ожидание статусных бит с обработкой ошибок и антизацикливанием
    static inline bool waitISRBitSet()
    {
      uint32_t sr;
      uint32_t timeout_counter=1'000'000;
      do 
      {
        sr=base()->ISR;
        if(sr&( I2C_ISR_NACKF | I2C_ISR_ARLO | I2C_ISR_BERR))
        {
          base()->ICR = I2C_ICR_NACKCF | I2C_ICR_BERRCF | I2C_ICR_ARLOCF;
          return false;      
        }
        if(--timeout_counter == 0) return false;
      }
      while( !(sr&Bit) );
      return true;
    }

     

    Тут base() понимать как I2C1, I2C2 и т.д. Эта функция член класса позволяет "протащить" указатель на периферию в constexpr контекст. Без плюсов можно просто указателем на I2C_TypeDef обойтись.

    template<uint32_t PI2C>
    class TI2C
    {  
      static inline auto base() { return (I2C_TypeDef *)PI2C;  }
    }

     

    Если надо передавать много, то чуть сложнее

    Спойлер

     

    bool MasterWrite(const uint8_t hw_adr, uint8_t *data, uint32_t len)
    {
      bool first_part = true;      
      while(len)
      {
        if(len<256)        
        {
          base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,len) | hw_adr | I2C_CR2_AUTOEND | (first_part?I2C_CR2_START:0);
          while(len)
          {
            if(!waitISRBitSet<I2C_ISR_TXIS>()) return false;
            base()->TXDR = *data++;
            len--;
          }
        }
        else
        {
          base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,255) | hw_adr | I2C_CR2_RELOAD | (first_part?I2C_CR2_START:0);
          first_part=false;
          for(uint32_t i=255; i--;) 
          {
            if(!waitISRBitSet<I2C_ISR_TXIS>()) return false;
            base()->TXDR = *data++;          
          } 
          if(!waitISRBitSet<I2C_ISR_TCR>()) return false;
          len-=255;
        }
      }    
      return true;
    }

     

    Оба случая можно под шаблон объединить

    Спойлер

     

    template<typename TLen>
    static inline bool MasterWrite(const uint8_t hw_adr, uint8_t *data, TLen len)
    {
      if constexpr(sizeof(TLen)==1)
      {      
        base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,len) | hw_adr | I2C_CR2_AUTOEND | I2C_CR2_START;
        while(len--)
        {
          if(!waitISRBitSet<I2C_ISR_TXIS>()) return false;
          base()->TXDR = *data++;
        }    
      }
      else
      {
        bool first_part = true;      
        while(len)
        {
          if(len<256)        
          {
            base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,len) | hw_adr | I2C_CR2_AUTOEND | (first_part?I2C_CR2_START:0);
            while(len)
            {
              if(!waitISRBitSet<I2C_ISR_TXIS>()) return false;
              base()->TXDR = *data++;
              len--;
            }
          }
          else
          {
            base()->CR2 = _VAL2FLD(I2C_CR2_NBYTES,255) | hw_adr | I2C_CR2_RELOAD | (first_part?I2C_CR2_START:0);
            first_part=false;
            for(uint32_t i=255; i--;) 
            {
              if(!waitISRBitSet<I2C_ISR_TXIS>()) return false;
              base()->TXDR = *data++;          
            } 
            if(!waitISRBitSet<I2C_ISR_TCR>()) return false;
            len-=255;
          }
        }    
      }
      return true;
    }

     

     

  12. Данные в памяти размещает линкер. У keil линкером команует так называемый скаттер-файл. Заводите в нём секцию по нужному адресу и размещаете в ней свою константу.

     

    А ещё, пятой точкой чую, что фигню какую-то хотите сделать и вам это не надо 🙂

×
×
  • Создать...