terça-feira, 7 de outubro de 2025

Velocidade de escrita máxima no Raspberry PI PICO

     Olá! vamos verificar qual a velocidade máxima que alcançamos usando o RASPBERRY PI PICO , pois mesmo que o processador interno seja rápido, as portas logicas podem não acompanhar essa velocidade, que inclusive foi o que ocorreu com este teste.
     Assim mesmo que faça um overclock no microcontrolador ou microprocessador isso não necessariamente se traduz em ganho de velocidade, pois ao atingir a frequência máxima de chaveamento do dispositivo ele simplesmente ficara em determinado nível de tensão e não conseguirá ter um tempo de decaimento e acionamento de sinal que o faca alternar entre os extremos do nível baixo e alto.
     Para conseguir mais rapidez no Raspberry tive que recorrer a diretiva  "sio_hw->gpio_set" que
consegue ser mais rápido do que a "digitalWrite" vamosaos trecho que código com um clock
de 200MHZ, cheguei a fazer overclock mas o ganho foi pouco e o risco de alguns
periféricos não funcionar corretamente também aumenta.
Para o primeiro utilizei o pino 14 e fiz o teste:

for(;;)
  {
     digitalWrite(14, HIGH);
     digitalWrite(14, LOW);
}

o que deu um sinal de 403ns em nivel baixo e 423ns em nivel alto. prosseguindo para o próximo teste fiz:

void loop()

{

int conta =0;

for(;;)

  {
       conta++;
       if(conta==6)
       {
          sio_hw->gpio_set = 1ul << (14 & 0x1fu);//acessar diretamente o pino
       }
       if(conta>12)
       {
         sio_hw->gpio_clr = 1ul << (14 & 0x1fu); // faz operação E com o pino a ser acessado
         conta =0;
       }
}
}
Assim utilizei os ciclo de maquina como base de tempo mas os menores valores foram de 6 ciclos
menor que isso o sinal não alterna mais.
com isso consegui 208ns em nível baixo e 234ns em nível alto um ganho de aproximadamente
50%.
Se tiver alguma sugestão ou duvida deixe ai nos comentários.
Até a próxima!


 

sexta-feira, 29 de agosto de 2025

Acionando fita de leds (WS2812) endereçável sem nenhuma biblioteca externa.

    Olá amigos! aqui vou demonstrar como acionar a fita de leds WS2812 usando o ESP32, e usando o mesmo raciocínio é possível portar este código pra qualquer microcontrolador que consiga rodar numa frequência rápida o suficiente para gerar os sinais. 

    Como sempre recomendo a ler o datasheet da fita que você quer acionar pois estes tempos dos bits podem variar conforme o modelo de fita utilizado. Claro que você também pode usar uma biblioteca pronta como a "FASTLED" porém o intuito aqui é desmistificar o pensamento de que é difícil controlar os leds.  

// CLIENTE: microcontroladores-c

// AUTOR: Aguivone M. Fógia
// HARDWARE: ESP32
// CONFIG = FREQUENCIA CPU ->240MHZ  e FREQUENCIA FLASH -> 80MHZ
////////////////////////////////////////////////////
//acionando fita de led WS2812 sem usar nenhuma biblioteca
/////////////////////////////////////////////////////
void setup()
{
  pinMode(13, OUTPUT); //pino D13
}
void BIT_0()//bit 0
{   // para outros modelos de fitas consultar datasheet
   for(int a=0 ; a<8; a++)//aprox.400ns
   {//só repete
     REG_WRITE(GPIO_OUT_W1TS_REG, BIT13);
   }
    for(int a=0; a<16; a++)//aprox.850ns
   {
     REG_WRITE(GPIO_OUT_W1TC_REG, BIT13);
   }
}
void BIT_1()//bit 1
{// para outros modelos de fitas consultar datasheet  
   for(int a=0 ; a<17; a++)//aprox.800ns
   {//só repete
     REG_WRITE(GPIO_OUT_W1TS_REG, BIT13);
   }
    for(int a=0; a<7; a++)//aprox.450ns
   {
     REG_WRITE(GPIO_OUT_W1TC_REG, BIT13);
   }
}
void pacote(char BLUE,char RED,char GREEN)//1 pacote de 24bits
{
    uint32_t dados = (GREEN<<16) + (RED<<8) + BLUE;//verificar sequencia  
    uint32_t aux = 1;
    while(aux<0X1000000)
    {
        if((dados & aux)>1)
        {//bit 1
          BIT_1();
        }
        else
        {
          BIT_0();
        }
        aux = aux<<1;
    }
}
void apagar_fita(long num_leds)
{
  long aux = 0;
  num_leds = num_leds*24; // 24bits por led
   while(aux<num_leds)
    {
      BIT_0();
      aux++;
    }
}
void preencher_fita(long num_leds)
{//com as 3 cores é mais rapido assim // cor branca
  long aux = 0;
  num_leds = num_leds*24; // 24bits por led
   while(aux<num_leds)
    {
      BIT_1();
      aux++;
    }
}
void preencher_cor(char GREEN,char RED,char BLUE,long num_leds)
{//preenche com a cor desejada
  long aux = 0;
   num_leds++;
   while(aux<num_leds)
    {
      pacote(GREEN,RED,BLUE);//só repete o pacote
      aux++;
    }
     
}
void preencher_cor_tempo(char GREEN,char RED,char BLUE,long num_leds,long milisegundos)
{//preenche com a cor desejada de tempo em tempo
  long aux = 1;
   while(aux<num_leds)
    {
      preencher_cor(GREEN,RED,BLUE,aux);//só repete o pacote
      aux++;
      delay(milisegundos);
    }
     
}
void move_ponto(char GREEN,char RED,char BLUE,long Pos)
{
   uint32_t dados = (GREEN<<16) + (RED<<8) + BLUE;//verificar sequencia  
   apagar_fita(Pos-1);    
    uint32_t aux = 1;
    while(aux<0X1000000)
    {
        if((dados & aux)>1)
        {//bit 1
          BIT_1();
        }
        else
        {
          BIT_0();
        }
        aux = aux<<1;
    }
}

void loop()
{
  apagar_fita(500);//limpa fita toda(ver numero de leds totais)
  for(;;)
  {
  // a barra vai sendo preencida ate um determinado led e depois apaga e começa novamente
    preencher_cor_tempo(0,25,0,49,200);
    apagar_fita(100);//se quiser apagar toda a fita colocar o numero total de leds
    delay(500);
    move_ponto(0,25,0,5);
    delay(100);
    move_ponto(0,25,0,10);
    delay(100);
    move_ponto(0,25,0,20);
    delay(100);
    move_ponto(0,25,0,30);
    delay(100);
    move_ponto(0,25,0,40);
    delay(100);
    move_ponto(0,25,0,50);
    delay(100);
  }
}

Olá fiz algumas alterações para funcionar para outros modelos e fiz melhoramentos
no código, veja como ficou minha segunda versão 20 dias depois:
// CLIENTE: microcontroladores-c
// AUTOR: Aguivone M. Fógia
// HARDWARE: ESP32
// CONFIG = FREQUENCIA CPU ->240MHZ  e FREQUENCIA FLASH -> 80MHZ
/////////////////////////// escolha qual será a fita de leds a ser utilizadas //////////////////////////////////////////////////////
//acionando fita de led WS2811 sem usar nenhuma biblioteca
//parametros:
/*
#define T0H  10   // aprox.500ns
#define T0L  35  //aprox.2000ns

#define T1H  24  //aprox.1200ns
#define T1L  26   //aprox.1300ns
*/
//acionando fita de led WS2812B sem usar nenhuma biblioteca
//parametros:
#define T0H  8   // aprox.400ns
#define T0L  16  //aprox.800ns

#define T1H  17  //aprox.850ns
#define T1L  7   //aprox.450ns

#define T_FIM  24   //será a soma das duas anteriores

//acionando fita de led WS2815B sem usar nenhuma biblioteca
//parametros:
/*#define T0H  6   // aprox.300ns
#define T0L  16  //aprox.850ns

#define T1H  16  //aprox.800ns
#define T1L  7   //aprox.370ns */

void setup()
{
  pinMode(13, OUTPUT);
}

void UM_BIT(char Temp) /// colocar T0H ou T1H
{
    REG_WRITE(GPIO_OUT_W1TS_REG, BIT13);
    for(int a=0 ; a<Temp; a++)
    {//só repete  
    NOP();  
    }
    REG_WRITE(GPIO_OUT_W1TC_REG, BIT13);
    for(int a=0; a<T_FIM; a++)
    {
      NOP();    
    }
}
void pacote(char BLUE,char RED,char GREEN)//1 pacote de 24bits
{
    uint32_t dados = (GREEN<<16) + (RED<<8) + BLUE;//verificar sequencia  
    uint32_t aux = 1;
    while(aux<0X1000000)
    {
        if((dados & aux)>1)
        {//bit 1
          UM_BIT(T1H);
        }
        else
        {
          UM_BIT(T0H);
        }
        aux = aux<<1;
    }
}
void apagar_fita(long num_leds)
{
  long aux = 0;
  num_leds = num_leds*24; // 24bits por led
   while(aux<num_leds)
    {
      UM_BIT(T0H);
      aux++;
    }
}
void preencher_fita(long num_leds)
{//com as 3 cores é mais rapido assim // cor branca
  long aux = 0;
  num_leds = num_leds*24; // 24bits por led
   while(aux<num_leds)
    {
      UM_BIT(T1H);
      aux++;
    }
}
void preencher_cor(char GREEN,char RED,char BLUE,long num_leds)
{//preenche com a cor desejada
  long aux = 0;
   num_leds++;
   while(aux<num_leds)
    {
      pacote(GREEN,RED,BLUE);//só repete o pacote
      aux++;
    }
     
}
void preencher_cor_tempo(char GREEN,char RED,char BLUE,long num_leds,long milisegundos)
{//preenche com a cor desejada de tempo em tempo
  long aux = 1;
   while(aux<num_leds)
    {
      preencher_cor(GREEN,RED,BLUE,aux);//só repete o pacote
      aux++;
      delay(milisegundos);
    }
     
}
void move_ponto(char GREEN,char RED,char BLUE,long Pos)
{
   uint32_t dados = (GREEN<<16) + (RED<<8) + BLUE;//verificar sequencia  
   apagar_fita(Pos-1);    
    uint32_t aux = 1;
    while(aux<0X1000000)
    {
        if((dados & aux)>1)
        {//bit 1
          UM_BIT(T1H);
        }
        else
        {
          UM_BIT(T0H);
        }
        aux = aux<<1;
    }
}

void loop()
{
  apagar_fita(500);//limpa fita toda(ver numero de leds totais)
  for(;;)
  {
  // a barra vai sendo preencida ate um determinado led e depois apaga e começa novamente
    preencher_cor_tempo(0,25,0,49,200); // preenche piscando.
    apagar_fita(100);//se quiser apagar toda a fita colocar o numero total de leds
    delay(500);
    move_ponto(0,25,0,5); // cor vermelha em 10% do brilho
    delay(200);
    move_ponto(0,25,0,10);
    delay(200);
    move_ponto(0,25,0,20);
    delay(200);
    move_ponto(0,25,0,30);
    delay(200);
    move_ponto(0,25,0,40);
    delay(200);
    move_ponto(0,25,0,50);
    delay(200);
    apagar_fita(100);
    delay(200);
  }
}



bom projetos pra vocês!

quarta-feira, 27 de agosto de 2025

Conseguindo melhorar a velocidade dos pinos do ESP32 e ESP8266 - análise de desempenho.

 Olá quando se precisa de tempos na escalas de nanosegundos se torna um problema para muitas placas e módulos utilizados no ARDUINO, então se recorre a módulos mais velozes como o ESP32 ou ESP8266. Porem temos a surpresa de mesmo sendo tão velozes não conseguimos acionar de forma pulsada na escala de nanosegundos ou até 20 microssegundos, pois abaixo disso nestes módulos começa a fazer diferenças os pequenos atrasos de tempo nas rotinas de tempo e com a função "digitalWrite".

configuração do módulo, a 240Mhz,logo cada ciclos de máquina levaria 4,16ns, o que :

Vamos a nosso plano de análise com um trecho de código fonte simples, onde apenas vamos
ligar de desligar o pino 13(D13) do módulo ESP32, a mesma analise vale para o ESP8266.
Note que em vez de colocar pino D0,D1,D2 ... podemos usar os define de sistema BIT0,BIT1,
BIT2 ... ou seja não precisa memorizar qual o valor em hexadecimal da posição de cada
pino. porém o tempo será diferente.

Veja o trecho de código:
//demontrando a diferença entre usar digitalWrite e REG_WRITE
void setup()
{
  pinMode(13, OUTPUT); //pino D13
}
void loop()
{
  digitalWrite(13, HIGH);
  delayMicroseconds(1);
  digitalWrite(13, LOW);
  delayMicroseconds(1);
  REG_WRITE(GPIO_OUT_W1TS_REG, BIT13); // é um define do arduino que vale 0X2000
  delayMicroseconds(1);
  REG_WRITE(GPIO_OUT_W1TC_REG, BIT13);
  delayMicroseconds(1);

}

Para o primeiro teste:

//demontrando a diferença entre usar digitalWrite e REG_WRITE
void setup()
{
  pinMode(13, OUTPUT); //pino D13
}
void loop()
{
  digitalWrite(13, HIGH);
  delayMicroseconds(1);
  digitalWrite(13, LOW);
  delayMicroseconds(1);
  /*REG_WRITE(GPIO_OUT_W1TS_REG, BIT13);
  delayMicroseconds(1);
  REG_WRITE(GPIO_OUT_W1TC_REG, BIT13);
  delayMicroseconds(1);*/

}

Para o segundo teste:

//demontrando a diferença entre usar digitalWrite e REG_WRITE
void setup()
{
  pinMode(13, OUTPUT); //pino D13
}
void loop()
{
  /*digitalWrite(13, HIGH);
  delayMicroseconds(1);
  digitalWrite(13, LOW);
  delayMicroseconds(1);*/
  REG_WRITE(GPIO_OUT_W1TS_REG, BIT13);
  delayMicroseconds(1);
  REG_WRITE(GPIO_OUT_W1TC_REG, BIT13);
  delayMicroseconds(1);
}

Para o terceiro teste:

//demontrando a diferença entre usar digitalWrite e REG_WRITE
void setup()
{
  pinMode(13, OUTPUT); //pino D13
}
void loop()
{
  //digitalWrite(13, HIGH);
  delayMicroseconds(1);
  //digitalWrite(13, LOW);
  delayMicroseconds(1);
  /*REG_WRITE(GPIO_OUT_W1TS_REG, BIT13);
  delayMicroseconds(1);
  REG_WRITE(GPIO_OUT_W1TC_REG, BIT13);
  delayMicroseconds(1);*/
}

Para o quarto teste:

//demontrando a diferença entre usar digitalWrite e REG_WRITE
void setup()
{
  pinMode(13, OUTPUT); //pino D13
}
void loop()
{
  /*digitalWrite(13, HIGH);
  delayMicroseconds(1);
  digitalWrite(13, LOW);
  delayMicroseconds(1);*/
  REG_WRITE(GPIO_OUT_W1TS_REG, BIT13);
 // delayMicroseconds(1);
  REG_WRITE(GPIO_OUT_W1TC_REG, BIT13);
 // delayMicroseconds(1);
}
Agora vamos ao resultado dos testes, usando a rotina "delayMicroseconds(1)" :

digitalWrite -> 3,27us em nivel alto e 4,19us em nivel baixo.
REG_WRITE -> 1,54us em nivel alto e 1,54us em nivel baixo.

sem rotinas de tempo :

digitalWrite -> 529ns em nivel alto e 778ns em nivel baixo.
REG_WRITE -> 58ns em nivel alto e 252ns em nivel baixo.

vídeo de demonstração:




Conclusão:
    Veja a diferença que tivemos ao usar "REG_WRITE" em vez de "digitalWrite", dando até 10x
mais rapido em nivel alto e 3X mais rapido em nivel baixo, claro que se pode descer um
pouco mais e fazer em assembly conseguindo algo proximo dos 4,16ns esperado, porém fica
o alerta para aplicações criticas. um dos motivos dessas diferenças entre nível alto e baixo
é devido aos codigos que rodam por baixo dessas funções.
Espero que possa ajudar alguém essa simples e importante análise.





terça-feira, 17 de junho de 2025

Lendo o ADC do STM32 na IDE arduino

Olá, neste exemplo vou demonstrar como ler 2 entradas analógicas e imprimir pela serial do microcontrolador STM32F103C6T6 . O pino PA10 é o RX (ligado ao TX do PC) e o pino PA9 o TX (ligado ao RX do PC).Veja que o código é bem simples:


#define LED    PC13

  //#define BOTAO  PA7  não sera usado
  #define A0  PA0
  #define A1  PA1

 bool status_led=0;

void setup() {
Serial.begin(9600);
  pinMode(BOTAO, INPUT);  // botao
  pinMode(LED, OUTPUT);  // led de status
  pinMode(A0, INPUT);  // configura entradas analogicas
  pinMode(A1, INPUT);
}

void loop() {
  // variavei para ler AN0 e AN1
  int canal0 = analogRead(A0);
  int canal1 = analogRead(A1);
  // imprime os valores
  Serial.print("canal_A0:");
  Serial.print(canal0);
  Serial.println(",");
  Serial.print("canal_A1:");
  Serial.println(canal1);

    if(status_led == 0) // pisca led
    {
        digitalWrite(LED, HIGH);
        status_led = 1;
    }
    else
    {
        digitalWrite(LED, LOW);
        status_led = 0;
    }  
  delay(300);

}

segunda-feira, 16 de junho de 2025

Comunicação serial 232 modo DMA usando o CUBE IDE no STM32F103C6T6

     Olá, veja a demonstração como usar o recurso DMA do microcontrolador da STM32, pois este recurso permite que a CPU do microcontrolador não pare de funcionar  a cada recepção de caracteres que chegam pela serial. Vale lembrar que também é possível configurar este recuso para transmissão, ou seja pode se colocar um vetor(array) para transmissão e então habilitar (ou não) para que ao finalizar gere uma interrupção de envio de todos os dados. aqui será usado a interface gráfica do CUBE IDE.

    Aqui estou usando o microcontrolador STM32F103C6T6 da placa de desenvolvimento blue pill.

configurando o CUBE IDE :

    Basta seguir as imagens para configurar corretamente. Na primeira imagem da aba "PINOUT & CONFIGURATION -> NVIC Setting"  deve estar habilitado as 2 interrupção de DMA e global, pois uma e para coletar os caractere e a outra é acionada quando o DMA atingir o numero de caracteres configurado, observe que na interface gráfica os pinos configurados são destacados.

    Na aba DMA Settings habilita USART_RX, mas se quiser habilitar pra transmissão use o USART_TX

    Na aba Parameter Settings configure a porta serial. 

    Neste exemplo usei o cristal externo na aba RCC, porem se quiser usar o clock interno fique a vontade, pois a propria IDE faz os ajuste automaticamente neste parâmetros, quando se seta na aba "CLOCK CONFIGURATION" .

Pronto ! agora é codificar

O código fonte :


    Pra quem usa o CUBE IDE sabe que ele irá gerar automaticamente o código da estrutura "main.c" quando se salva as configurações portanto é necessário acrescentar apenas algumas variáveis e as chamadas de interrupções, neste caso utilizei a de recepção completa(HAL_UART_RxCpltCallback) mas existe a opção de avaliar quando se chega metade dos dados(HAL_UART_RxHalfCpltCallback), caso precise validar um pacote grande pode ser util. 
    Na rotina principal não precisaria ter nada, porém coloquei uma variável para demonstrar caso seja necessário fazer alguma ação depois que recebe o vetor com os dados recebidos.

#include "main.h"

#include <stdio.h>

UART_HandleTypeDef huart1;

DMA_HandleTypeDef hdma_usart1_rx;


/* USER CODE BEGIN PV */

/* USER CODE END PV */


/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_DMA_Init(void);

static void MX_USART1_UART_Init(void);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */


/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

#define TX_BUFFER_SIZE 128 // Tamanho do buffer de transmissão


uint8_t RxData[20]; //20 bytes de recepção

uint8_t tem_dados = '0';


char txBuffer[TX_BUFFER_SIZE]; // Buffer para enviar mensagens de debug/resposta


void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)

{ //chegou a metade dos dados pode ser util em alguma aplicação

//HAL_UART_Transmit(&huart1,RxData, 10, 50); //imprime a metade coletada

}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{ //chegou a quantidade de dados escolhidos

HAL_UART_Receive_DMA(&huart1,RxData,10); // solicita novamente mais 10 bytes

tem_dados = '1';

HAL_UART_Transmit(&huart1,RxData, 10, 50);

int apaga=0;

while(apaga<20)//limpa pacote

{

RxData[apaga] =' ';

apaga++;

}


}


/* USER CODE END 0 */


/**

* @brief The application entry point.

* @retval int

*/

int main(void)

{


/* USER CODE BEGIN 1 */

/* USER CODE END 1 */


/* MCU Configuration--------------------------------------------------------*/


/* Reset of all peripherals, Initializes the Flash interface and the Systick. */

HAL_Init();


/* USER CODE BEGIN Init */

/* USER CODE END Init */


/* Configure the system clock */

SystemClock_Config();


/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */


/* Initialize all configured peripherals */

MX_GPIO_Init();

MX_DMA_Init();

MX_USART1_UART_Init();

/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

HAL_UART_Receive_DMA(&huart1,RxData,10);

/* Infinite loop */

/* USER CODE BEGIN WHILE */

/* USER CODE END WHILE */

HAL_UART_Transmit(&huart1, (uint8_t*)"Sistema Pronto. Aguardando dados...\n\r", strlen("Sistema Pronto. Aguardando dados...\n\r"), HAL_MAX_DELAY);

for(;;)

{

if(tem_dados == '1')

{

tem_dados = '0';

HAL_UART_Transmit(&huart1, (uint8_t*)"chegou dados!", strlen("chegou dados!"), HAL_MAX_DELAY);

}

}

/* USER CODE BEGIN 3 */

/* USER CODE END 3 */

}


/**

* @brief System Clock Configuration

* @retval None

*/

void SystemClock_Config(void)

{

RCC_OscInitTypeDef RCC_OscInitStruct = {0};

RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};


/** Initializes the RCC Oscillators according to the specified parameters

* in the RCC_OscInitTypeDef structure.

*/

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

RCC_OscInitStruct.HSEState = RCC_HSE_ON;

RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;

if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

{

Error_Handler();

}


/** Initializes the CPU, AHB and APB buses clocks

*/

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK

|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;

RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;

RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;


if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)

{

Error_Handler();

}

}


/**

* @brief USART1 Initialization Function

* @param None

* @retval None

*/

static void MX_USART1_UART_Init(void)

{


/* USER CODE BEGIN USART1_Init 0 */

/* USER CODE END USART1_Init 0 */


/* USER CODE BEGIN USART1_Init 1 */

/* USER CODE END USART1_Init 1 */

huart1.Instance = USART1;

huart1.Init.BaudRate = 9600;

huart1.Init.WordLength = UART_WORDLENGTH_8B;

huart1.Init.StopBits = UART_STOPBITS_1;

huart1.Init.Parity = UART_PARITY_NONE;

huart1.Init.Mode = UART_MODE_TX_RX;

huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;

huart1.Init.OverSampling = UART_OVERSAMPLING_16;

if (HAL_UART_Init(&huart1) != HAL_OK)

{

Error_Handler();

}

/* USER CODE BEGIN USART1_Init 2 */

/* USER CODE END USART1_Init 2 */


}


/**

* Enable DMA controller clock

*/

static void MX_DMA_Init(void)

{


/* DMA controller clock enable */

__HAL_RCC_DMA1_CLK_ENABLE();


/* DMA interrupt init */

/* DMA1_Channel5_IRQn interrupt configuration */

HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);


}


/**

* @brief GPIO Initialization Function

* @param None

* @retval None

*/

static void MX_GPIO_Init(void)

{

GPIO_InitTypeDef GPIO_InitStruct = {0};

/* USER CODE BEGIN MX_GPIO_Init_1 */

/* USER CODE END MX_GPIO_Init_1 */


/* GPIO Ports Clock Enable */

__HAL_RCC_GPIOC_CLK_ENABLE();

__HAL_RCC_GPIOD_CLK_ENABLE();

__HAL_RCC_GPIOA_CLK_ENABLE();


/*Configure GPIO pin Output Level */

HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);


/*Configure GPIO pin : LED_Pin */

GPIO_InitStruct.Pin = LED_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);


/* USER CODE BEGIN MX_GPIO_Init_2 */

/* USER CODE END MX_GPIO_Init_2 */

}


/* USER CODE BEGIN 4 */

/* USER CODE END 4 */


/**

* @brief This function is executed in case of error occurrence.

* @retval None

*/

void Error_Handler(void)

{

/* USER CODE BEGIN Error_Handler_Debug */

/* USER CODE END Error_Handler_Debug */

}


#ifdef USE_FULL_ASSERT

/**

* @brief Reports the name of the source file and the source line number

* where the assert_param error has occurred.

* @param file: pointer to the source file name

* @param line: assert_param error line source number

* @retval None

*/

void assert_failed(uint8_t *file, uint32_t line)

{

/* USER CODE BEGIN 6 */

/* USER CODE END 6 */

}

#endif /* USE_FULL_ASSERT */


Obrigado pela atenção! e até a próxima postagem. Data: 16/06/2025