Авг 31

STM32 и malloc во внешней памяти FMC / SDRAM

После того, как FMC/FSMC запустился и работает, внешняя память отражается по соответствующим адресам. Эту память можно использовать по захардкоденным адресам

char * ptr = (char*)0xC0000000;

но каждый раз вычислять адреса не комильфо. Тем более, для этого как раз есть специальная штука — heap и malloc/free.
Нужно только рассказать malloc где у нас эта память и сколько её. Самый простой способ — исправить правила линковки: Суть такова. _sbrk использует память начиная c адреса переданного линковщиком как end, стоит положить его адрес SDRAM, как malloc начинает раздавать адреса из неё.
например из соответствующих правил сборки грохнуть

PROVIDE( end = .)

и дописать свой:

end = 0xC000000;

Или добавить полноценно, в описании памяти добавить регион SDRAM

MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 1024K
SDRAM(rw)       : ORIGIN = 0xC0000000, LENGTH = 8M
}

и добавить секцию в раздел SECTIONS:

 ._user_heap(NOLOAD) :
  {
    PROVIDE(_heap_start = .);
    PROVIDE ( end = . );
    . += LENGTH(SDRAM);
    PROVIDE(_heap_end = .);
  }  >SDRAM

или (если не нравится, что size показывает дофига) без секции:

_heap_start = ORIGIN(SDRAM);
_heap_end = ORIGIN(SDRAM)+LENGTH(SDRAM);

А символы _heap_start и _heap_end будем использовать в своей реализации _sbrk, которая еще проверит не вылезаем ли мы за размер:

#include <stdlib.h>
#include <errno.h>
 
caddr_t _sbrk(int incr) {
    extern uint8_t _heap_start;
    extern uint8_t _heap_end;
 
    static uint8_t *current_end = NULL;
    uint8_t *current_block_address;
 
    if (!current_end)
        current_end = &_heap_start;
 
    current_block_address = current_end;
 
    incr = (incr + 3) & (~3);
    if (current_end + incr > &_heap_end) {
        errno = ENOMEM;
        return (caddr_t) -1;
    }
    current_end += incr;
    return (caddr_t) current_block_address;
 
}
Апр 27

AVR CMake

Clion & AVRВот уже несколько лет пользуюсь CMake-ом, чтобы собирать проекты под AVR. Сподвиг на этом конечно же вышедший осенью 2014 Jetbrains CLion, который как оказалось идеально подходит для написания кода под Atmel AVR. Короче, рекомендую.
Возможно, для корректной работы нужно будет установить переменную среды AVR_FIND_ROOT_PATH — на папку с avr (содержащую lib и include), а так же папка с avr-gcc, avr-g++, avr-objcopy, avr-size должны находиться в PATH. Ну или доработать напильником generic-gcc-avr.cmake

В общем, шаблон тут: https://github.com/bevice/avr_cmake_template
Continue reading

Окт 15

Аппаратный I2C (TWI) в микроконтроллерах AVR

При наличии на борту AVR аппаратной реализации I2C почему-то многие предпочитают программные реализации. Хотя, на мой скромный взгляд — использование железного варианта проще, стабильнее и удобнее.

Применение встроенного интерфейса и подразумевает работу на прерываниях, но сегодня мы обойдемся без оных. Для понимания работы контроллера это несколько проще, а переложить код на использование прерываний не составит труда.

Описывать шину I2C не имеет смысла, исчерпывающие описание можно найти на википедии, Казусе и конечно у DI HALT’a. Последняя ссылка заслуживает особого внимания, там основное внимание уделяется именно AVR, но в качестве примеров используется RTOS, что несколько абстрагирует от последовательности работы. Именно для того, чтобы дополнить статью DI HALT’a (а так же, чтобы не забыть что и как самому) и была написана эта небольшая заметка.
Continue reading