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

Сергей Борщ

Модератор
  • Постов

    10 921
  • Зарегистрирован

  • Посещение

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

    31

Сообщения, опубликованные Сергей Борщ


  1. 4 часа назад, AzardCry сказал:

    нужно указать ключ -cpp в закладке C/C++

    Насколько я понимаю - вы заставили принудительно все файлы (включая библиотеку SPL) компилироваться в режиме C++. Не думаю, что это правильное решение - языки отличаются и не всякий C-код будет собираться как код C++. А надо было просто разобраться, почему включаемые в ваш main.cpp объявления C-функций не имеют спецификатора extern "C".

     

  2. Если вылетает "сразу" - вполне возможно, что вы выбрали в среде разработки модель с бОльшим количеством памяти, чем есть в вашем контроллере. Поэтому компилятор разместил стек в несуществующей памяти и первая же инструкция записи на стек приводит к исключению. Самый простой и быстрый (на мой взгляд) способ проверить это - вставить в программу вот такой обработчик исключения HardFault:

    void HardFault_Handler(void)
    {
        volatile int i = 0;
        while(!i)
            ;
    }

    Попав в него вы переводите отладчик в режим исполнения ассемблерных команд (не помню, как это делается в Кейле - возможно, надо открыть и сделать активным окно дизассемблера), через отладчик заносите в i любое не равное 0 значение и двигаясь по ассемблерным командам выходите из обработчика. Попадаете на следующую инструкцию после той, которая вызвала исключение. Смотрите на нее, смотрите на содержимое использованных в ней регистров, думаете, почему там появились именно эти значения и какими они должны быть для правильной работы. Если же вы попадаете куда-то за пределы памяти программ - тогда все несколько сложнее, можно и книги Ю читать или тупо несколько раз выполнить программу с самого начала по ассемблерным командам найдя ту, на которой происходит падение.

  3. 1 час назад, Aries сказал:

    Как влиять на это ???

    Один и тот же результат операции может быть достигнут разными командами. Даже ассемблер пытается делать программу компактной и быстрой, а вы хотите делать ее большой и медленной (доля шутки). То есть заставить чистый ассемблер ставить неоптимальный код команды в одно конкретное место скорее всего будет невозможно. Единственное, что здесь может сработать - использовать связку ассемблер-компоновщик (линкер) и команду занесения в регистр неизвестной ассемблеру константы, подставляемой компоновщиком. Поскольку значение константы асссемблеру неизвестно - он будет вынужден поставить подходящий для произвольной константы более длинный и медленный код. И останется только надеяться, что компоновщик именно вашей версии IARа не умеет оптимизировать выходной код или эту оптимизацию можно принудительно отключить. Как это сделать конкретно в современном IAR я не знаю и присоединяюсь к совету jcxz почитать про раздельную компиляцию и работу компоновщика.

  4. 50 минут назад, djhall сказал:

    но в этот раз появилось сообщение, что овальные отверстия не могут быть просверлены.

    Откуда появилось сообщение?

     

    Кикад пихает и овальные и круглые отверстия в один файл. JLCPCB делает по этим файлам платы с круглыми и овальными отверстиями без вопросов.

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

    А std::aligned_storage это что-то наподобие __attribute__((aligned(x)))?

    Слушать аудиосказку Вовка в тридевятом царстве (1965 г.)

    https://en.cppreference.com/w/cpp/types/aligned_storage

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

    Просто какой способ правильнее - атрибутами задать выравнивание и т.д., либо этим aligned_storage?

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

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

    Объясните, пожалуйста, на пальцах, если не трудно.

    std::aligned_storage резервирует память необходимого размера и с необходимым выравниванием с гарантией отсутствия неопределенного поведения.

    placement new располагает в этой области необходимую вам структуру и возвращает указатель на нее. Дальше можно работать с этим указателем, мне больше нравится работать со ссылкой. Эта структура должна иметь конструктор, который не делает с этой структурой ничего (в данном случае это конструктор по умолчанию).

    #include    <type_traits>
    std::aligned_storage<sizeof(uint32_t), alignof(uint32_t)> Buffer[512 / sizeof(uint32_t)];
    
    struct packet
    {
        uint32_t    A;
        uint16_t    B;
        uint8_t     C;
    };
    
    #include    <new>
    void test()
    {
        auto const & Packet = *(new(Buffer) packet);
    
        uint32_t A = Packet.A;
        uint16_t B = Packet.B;
        uint8_t  C = Packet.C;
    
    }

    Фактически placement new() приводит переданный ему указатель к нужному типу и вызывает конструктор с этим указателем. Программист должен гарантировать, что переданный в placement new() указатель отвечает всем требованиям к выравниванию и прочему, 

    • Upvote 2
  7. 2 часа назад, Arlleex сказал:

    приходят к примерно одному мнению - чтобы наложить структуру на буфер (я про подход, где гарантированно не будет проблем с активизацией членов union и strict aliasing), надо *боже дай мне сил не материться* скопировать этот буфер в объект такой структуры

    Есть еще вариант с placement new().

  8. 13 часов назад, Arlleex сказал:

    Идея ясна, спасибо.

    Вот, придумался более простой вариант:

    struct sendable {};
    struct a : public sendable
    {
    
    };
    struct b {};
    
    inline void send_msg(sendable const & from, size_t size)
    {
        auto pSrc = static_cast<void const *>(&from);
        ...............
    }
    
    template<typename T>
    void send_msg(T const & data)
    {
        send_msg(data, sizeof(T));
    }
    
    template<typename T, size_t items>
    void send_msg(T const (& data)[items])   // если вдруг потребуется передавать массив структур
    {
        send_msg(data[0], sizeof(T) * items);
    }
    
    void test()
    {
        a Good = {};
        a Good2[2] = {{}, {}};
        b Bad = {};
        send_msg(Good);
        send_msg(Good2);
        send_msg(Bad);  // error: no matching function for call to 'send_msg(const b&, unsigned int)'
                        // <- note:   no known conversion for argument 1 from 'const b' to 'const sendable&'
    }

     

    • Upvote 1
  9. 42 минуты назад, Arlleex сказал:

    Но, опять же, у Вас шаблонная функция, я бы хотел избежать этого

    Эта шаблонная функция тупо передает другой (нешаблонной) указатель и размер структуры. Результат проверки известен на этапе компиляции. То есть код шаблонной функции занимает ровно ноль лишних байтов. Вам бы все равно пришлось передавать указатель и размер вручную (с шансом ошибиться). Да, я забыл сделать ее inline, но компилятор, скорее всего, догадается сам.

  10. 1 час назад, Arlleex сказал:

    А функция отправки принимает любой из допустимых форматов, описанных в этой библиотеке. Соответственно, ее реализация одна, а принимает она некий общий тип.

    Я бы делал примерно так:

    struct sendable
    {
        enum class tag { OK };
        static constexpt tag Tag = tag::OK;
    };
    
    struct a : public sendable
    {
        ..............
    };
    
    struct b
    {
        ............
    };
    
    void send_msg(void const * from, size_t size);
    
    template<typename T>
    void send_msg(T const & data)   { if(data.Tag == sendable::tag::OK) send_msg(&data, sizeof(T)); }
      
      
    void test()
    {
    	a Good = {};
      	send_msg(Good);
      
      	b Bad = {};
      	send_msg(Bad);	// <-- compile error Bad has no member 'Tag'
    }

     

  11. 27 минут назад, Arlleex сказал:

    А Flash сделать обычной.

    Если ничего не путаю, GD изначально занималась флеш-памятью. То есть это не к готовому ядру прикрутили внешнюю флеш, а к готовой флешке прикрутили ядро.

  12. 3 часа назад, zheka сказал:

    в ячейке 0x1FFFF7E0  содержится 00 00 00 00 CA 5C 5A 1A    В правильном чипе  80 00 FF FF FF 58 4B 4A

    Какая-то лютая отбраковка без флеша вообще? Согласно документации размер флеша 0 килобайт:

    image.thumb.png.fa80bd914d754ebd1daac197fcc98548.png

    Бросьте каку 🤣

    Следом за первыми двумя байтами идет 96-битный уникальный ID, который может быть любым.

    3 часа назад, zheka сказал:

    Проверка показала, что Bits 26:24 SWJ_CFG[2:0]: Serial wire JTAG configuration - в принципе недоступны для записи

    В чем дело то?

    Надеюсь, вы перед обращением к этому регистру включаете его тактирование в RCC->APB2ENR.AFIO_EN?

  13. 25 минут назад, MrGalaxy сказал:

    неиспользованные выводы портов целесообразнее оставить неподключёнными или соединить с GND/Vcc?

    Оставить неподключенными и настроить на вывод.

     

    • Upvote 1
  14. 1 час назад, MrGalaxy сказал:

    или можно обращаться к отдельным элементам массива, не загружая его полностью?

    Разумеется, должно быть можно. Ведь даже чтобы загрузить этот массив в ОЗУ нужно обращаться к его отдельным элементам в памяти программ.

    Вот, из его документации:

    Цитата

    Шесть регистров из 32 могут использоваться как три 16-разрядных регистра косвенного адреса для эффективной адресации в пределах памяти данных. Один из этих указателей может также использоваться как указатель адреса для доступа к памяти программ.

     

    • Upvote 1
  15. 12 часов назад, zheka сказал:

    Не тот кристалл в не то корпус распаяли?

    Да, похоже на то. Мне (не на Али) в разгар кризиса поставщик привез партию F100, половина которой оказалась перемаркированными F103. Ваши либо 101xC/D/E, либо 103xC/D/E. Точнее букву можно узнать по содержимому ячейки 0x1FFFF7E0. А вот отличить 103 от 101, наверное, только по регистрам RCC->AHBENR, RCC->APBxENR - для 101 там не должны устанавливаться в 1 биты несуществующих таймеров, USB, CAN, SDIO.

  16. 5 часов назад, Variant99 сказал:

    Так это ж алгоритм DDS

    Именно. Имеем предварительно рассчитанную таблицу одного (половины/четверти/одной восьмой) периода в постоянной памяти, из которой с нужным шагом выбираем значения (на каких-то частотах каждое n-е значение, на каких-то одно и то же значение k раз), умножаем на необходимую амплитуду в формате фиксированной точки и кладем в массив в ОЗУ, из которого ПДП (DMA) в нужные моменты времени забирает данные в таймер. Заполнение половин массива ОЗУ в прерываниях окончания передачи (TIF) и окончания половины передачи (HTIF). Одно умножение на отсчет. Для остальных фаз то же самое со сдвигом на 1/3 и  2/3 исходной таблицы. У меня по такому принципу ATmega88 на 16 МГц успевала без ПДП и ассемблера в исходниках выдавать шесть фаз синуса 400 Гц из таблицы на 1/8 периода синуса, а STM32F100 на 24 МГц с ПДП формировать два FFSK без разрыва фазы на 1200/2400 не особо напрягаясь.

    У Л. И. Ридико прекрасная статья по реализации DDS.

  17. 5 часов назад, LAS9891 сказал:

    У меня на самом деле GD32F103RB, и тут я не нашёл System configuration controller

    Путаетесь в показаниях 🤨:

    В 01.03.2023 в 15:19, LAS9891 сказал:

    Есть stm32

    Сказали бы сразу про GD32 - я бы за вас его документацию почитал :biggrin:

  18. Если одна кнопка на PA0, вторая - на PB0, то только одна из них может быть настроена на EXTI. То есть исходная задача не решается вообще никак - только одна из кнопок на Px0 может вызывать прерывание. Одну из кнопок надо уносить на PxY, где X - любой, а Y != 0.

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