Eu realmente não queria me envolver na otimização de código, ao mesmo tempo em que adicionava problemas para encontrar novos bugs. Portanto, foi oportuno lembrar que esta versão do microcontrolador possui um segmento adicional de 64K RAM (CCM SRAM) a bordo, que não foi usado de forma alguma. Eureka - aqui está, a solução!
Mas, infelizmente, nem tudo foi tão simples.
Resultados da pesquisa para uma solução pronta
A documentação oficial do CCMRAM fornece exemplos para colocar código executável, uma pilha ou variáveis individuais nela.
A pesquisa nos fóruns resultou em vários links para maneiras diferentes de usar o CCMRAM, mas, infelizmente, eram todas variações diferentes das maneiras que foram descritas na documentação oficial. E todos eles exigiram uma análise profunda do código-fonte para adicionar atributos ao declarar cada função ou variável.
Para o GCC, no meu caso, algo assim:
__attribute__((section(".ccmram")));
Além disso, algumas variáveis têm um valor padrão, que requer a modificação do carregador de inicialização para que, quando o firmware iniciar, essas variáveis sejam copiadas para uma área separada para variáveis inicializadas ou zeradas.
Bem, a dificuldade final foram as limitações do próprio CCMRAM. Ele fica em um barramento separado ao qual o DMA não tem acesso e foi planejado para usar o acesso direto à memória de forma muito ativa.
Em outras palavras, ao resolver um problema, pode-se acidentalmente adicionar vários outros e cavar a depuração para encontrar os bugs introduzidos.
Felizmente, conseguimos encontrar uma solução simples por parte do FreeRTOS.
O tamanho do heap era menor que o tamanho do segmento de RAM CCM e a decisão era evidente - mover o heap para esta partição.
E conseguimos fazer isso com mudanças mínimas de código.
- Uma nova seção é adicionada ao arquivo ld (no meu caso STM32F407VGTX_FLASH.ld):
.ccmram : { . = ALIGN(8); . = . + _Min_Heap_Size; . = ALIGN(8); } >CCMRAM
- Na seção "._user_heap_stack" uma linha é comentada ou excluída
/* . = . + _Min_Heap_Size; */
As linhas com _Min_Heap_Size são necessárias para que o vinculador emita avisos em caso de tamanho de RAM insuficiente. - Uma única variável é adicionada ao corpo do programa.
uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__((section(".ccmram")));
- E ao construir um projeto, uma definição de pré-processador é adicionada
configAPPLICATION_ALLOCATED_HEAP=1
Como resultado - um monte de FreeRTOS no CCM SRAM com um número mínimo de edições no código-fonte!