Skocz do zawartości

Problem z RTC- Nucleo F103RB


Bhoy67

Pomocna odpowiedź

Witam 🙂

Mam problem z działaniem RTC na płytce Nucleo (tej, która była użyta w kursie Forbota jak widać z tytułu wątku). Pisałem program w SW4STM (bez użycia CubeMX), który miał wyświetlać aktualną godzinę na LCD tym samym, co we wspomnianym kursie (Nokia 5110). Z obsługą wyświetlacza nie ma żadnych problemów. Gdy to pisałem zacząłem od wyświetlenia trzech liczb dwucyfrowych (godzina:minuta:sekunda) i działało dobrze. Teraz, gdy RTC czasem odpali, to godzinę też pokazuje ok. Kod main wstawiam poniżej.

#include "stm32f1xx.h"
#include "font.h"
#include "lcd.h"

TIM_HandleTypeDef tim;
TIM_OC_InitTypeDef channel;
UART_HandleTypeDef uart;


void send_char(char c) {
	HAL_UART_Transmit(&uart, (uint8_t*)&c, 1, 1000);
}

int __io_putchar(int c) {
	if (c=='\n') {
		send_char('\r');
	}
	send_char(c);
	return c;
}

void Error_Handler(void) {
  printf("Error Handler!\n");
}

int main(void)
{
	HAL_Init();

	//konfiguracja zegarów- HSE + LSE- do RTC
	RCC_OscInitTypeDef osc;
	osc.OscillatorType=RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSI;
	osc.HSEState=RCC_HSE_ON;
	osc.HSEPredivValue=RCC_HSE_PREDIV_DIV1;
	osc.LSEState=RCC_LSE_OFF;
	osc.HSIState=RCC_HSI_OFF;
	osc.HSICalibrationValue=RCC_HSICALIBRATION_DEFAULT;
	osc.LSIState=RCC_LSI_ON;
	osc.PLL.PLLState=RCC_PLL_ON;
	osc.PLL.PLLSource=RCC_PLLSOURCE_HSE;
	osc.PLL.PLLMUL=RCC_PLL_MUL2;
	HAL_RCC_OscConfig(&osc);
	RCC_ClkInitTypeDef clk;
	clk.ClockType=RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
	clk.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;  //16MHz SYS;
	clk.AHBCLKDivider=RCC_SYSCLK_DIV1;
	clk.APB2CLKDivider=RCC_HCLK_DIV1;
	clk.APB1CLKDivider=RCC_HCLK_DIV2;  //8MHz- APB1
	HAL_RCC_ClockConfig(&clk, FLASH_LATENCY_1);

	__HAL_RCC_BKP_CLK_ENABLE();
	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();
	__HAL_RCC_GPIOC_CLK_ENABLE();
	__HAL_RCC_TIM4_CLK_ENABLE();
	__HAL_RCC_SPI1_CLK_ENABLE();
	__HAL_RCC_USART2_CLK_ENABLE();

	RCC_PeriphCLKInitTypeDef periphCLK;
	periphCLK.PeriphClockSelection=RCC_PERIPHCLK_RTC;
	periphCLK.RTCClockSelection=RCC_RTCCLKSOURCE_LSI;  //taktowanie RTC z LSI
	if (HAL_RCCEx_PeriphCLKConfig(&periphCLK) != HAL_OK) {
	    Error_Handler();
	}

	//konfiguracja GPIO
	GPIO_InitTypeDef gpio;
	gpio.Pin=LCD_Clk|LCD_Din;  //PA5- SPI1:SCK, PA7- MOSI
	gpio.Mode=GPIO_MODE_AF_PP;
	gpio.Pull=GPIO_NOPULL;
	gpio.Speed=GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOA, &gpio);
	gpio.Pin=GPIO_PIN_6;  //PB6- do podświetlenia z PWM
	HAL_GPIO_Init(GPIOB, &gpio);
	gpio.Pin=LCD_RST|LCD_DC|LCD_CE|GPIO_PIN_0;
	gpio.Mode=GPIO_MODE_OUTPUT_PP;
	HAL_GPIO_Init(GPIOC, &gpio);
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);  //testowy LED
	gpio.Pin=GPIO_PIN_2;  //PA2- Tx
	gpio.Mode=GPIO_MODE_AF_PP;
	HAL_GPIO_Init(GPIOA, &gpio);
	gpio.Pin=GPIO_PIN_3;  //PA3-Rx
	gpio.Mode=GPIO_MODE_AF_INPUT;
	HAL_GPIO_Init(GPIOA, &gpio);

	//konfiguracja UART
	uart.Instance=USART2;
	uart.Init.BaudRate=9600;
	uart.Init.WordLength=UART_WORDLENGTH_8B;
	uart.Init.StopBits=UART_STOPBITS_1;
	uart.Init.Parity=UART_PARITY_NONE;
	uart.Init.Mode=UART_MODE_TX_RX;
	uart.Init.HwFlowCtl=UART_HWCONTROL_NONE;
	uart.Init.OverSampling=UART_OVERSAMPLING_16;
	HAL_UART_Init(&uart);

	//konfiguracja timera TIM4:
	tim.Instance=TIM4;  //TIM4Ch1- PB6- podświetlacz
	tim.Init.Prescaler=160-1;  //16MHz na wejściu
	tim.Init.Period=100-1;  //PWM freq = 1kHz
	tim.Init.CounterMode=TIM_COUNTERMODE_UP;
	tim.Init.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE;
	tim.Init.ClockDivision=1-1;
	HAL_TIM_PWM_Init(&tim);
	channel.OCMode=TIM_OCMODE_PWM1;
	channel.Pulse=100;
	channel.OCPolarity=TIM_OCPOLARITY_HIGH;
	channel.OCFastMode=TIM_OCFAST_DISABLE;
	HAL_TIM_PWM_ConfigChannel(&tim, &channel, TIM_CHANNEL_1);

	HAL_TIM_PWM_Start(&tim, TIM_CHANNEL_1);

	//konfiguracja SPI1 do obsługi wyświetlacza:
	spi.Instance=SPI1;
	spi.Init.Mode=SPI_MODE_MASTER;
	spi.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_4;  //4MHz (max)
	spi.Init.Direction=SPI_DIRECTION_2LINES;
	spi.Init.DataSize=SPI_DATASIZE_8BIT;
	spi.Init.CLKPolarity=SPI_POLARITY_LOW;
	spi.Init.CLKPhase=SPI_PHASE_1EDGE;
	spi.Init.NSS=SPI_NSS_SOFT;
	spi.Init.FirstBit=SPI_FIRSTBIT_MSB;
	spi.Init.TIMode=SPI_TIMODE_DISABLE;
	spi.Init.CRCCalculation=SPI_CRCCALCULATION_DISABLE;
	spi.Init.CRCPolynomial=7;
	HAL_SPI_Init(&spi);

	__HAL_SPI_ENABLE(&spi);

	HAL_GPIO_WritePin(GPIOC, LCD_CE, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC, LCD_DC, GPIO_PIN_RESET);  //cmd (a nie data)

	lcd_setup();  //config

	/*lcd_draw_text(0,4,"Press button");
	lcd_draw_text(2,37,"to");
	lcd_draw_text(4,10,"START GAME!");
	lcd_copy();*/

	//konfiguracja RTC
	RTC_HandleTypeDef rtc;
	rtc.Instance=RTC;
	rtc.Init.AsynchPrediv=RTC_AUTO_1_SECOND;
	rtc.Init.OutPut=RTC_OUTPUTSOURCE_NONE;
	if (HAL_RTC_Init(&rtc) != HAL_OK) {
	    Error_Handler();
	}
	printf("Stan RTC: %i!\n", HAL_RTC_GetState(&rtc));
	
	RTC_TimeTypeDef time;
	time.Hours=11;  //13:34:50
	time.Minutes=17;
	time.Seconds=50;
	if (HAL_RTC_SetTime(&rtc, &time, RTC_FORMAT_BIN) != HAL_OK) {
		Error_Handler();
	}
	
	RTC_DateTypeDef date;
	date.WeekDay=RTC_WEEKDAY_THURSDAY;
	date.Month=RTC_MONTH_MARCH;
	date.Date=19;  //18.03.2020
	date.Year=20;
	if (HAL_RTC_SetDate(&rtc, &date, RTC_FORMAT_BIN) != HAL_OK) {
		Error_Handler();
	}

	while(1) {
		//wyświetlanie zegara
		RTC_TimeTypeDef timeWyn;
		HAL_RTC_GetTime(&rtc, &timeWyn, RTC_FORMAT_BIN);
		printf("%i : %i : %i\n", timeWyn.Hours, timeWyn.Minutes, timeWyn.Seconds);
		/*lcd_draw_time(&time);
		lcd_copy();*/
		HAL_Delay(1000);
	}
}

W terminalu otrzymuję wiadomość wysłaną przez UART, że stan RTC to HAL_RTC_STATE_ERROR (czyli kod 4). Nie wiedziałem co z tym zrobić i napisałem program w CubeMX, który tylko wysyła przez UART aktualną godzinę i tam wszystko działa. Zajrzałem do konfiguracji i widzę, że mam ją zrobioną identycznie chyba, że czegoś nie mogę dostrzec... Już nie będę spamował kodami, wyślę teraz tylko odpowiedni fragment tego kodu z CubeMX.

static void MX_RTC_Init(void)
{

  /* USER CODE BEGIN RTC_Init 0 */

  /* USER CODE END RTC_Init 0 */

  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef DateToUpdate = {0};

  /* USER CODE BEGIN RTC_Init 1 */

  /* USER CODE END RTC_Init 1 */
  /** Initialize RTC Only 
  */
  hrtc.Instance = RTC;
  hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
  hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }

  /* USER CODE BEGIN Check_RTC_BKUP */
    
  /* USER CODE END Check_RTC_BKUP */

  /** Initialize RTC and set the Time and Date 
  */
  sTime.Hours = 10;
  sTime.Minutes = 10;
  sTime.Seconds = 10;

  if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
  {
    Error_Handler();
  }
  DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
  DateToUpdate.Month = RTC_MONTH_JANUARY;
  DateToUpdate.Date = 1;
  DateToUpdate.Year = 20;

  if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN RTC_Init 2 */

  /* USER CODE END RTC_Init 2 */

}

A w funkcji main jedyny autorski fragment:

printf("Hello World!\n");
  while (1)
  {
	  RTC_TimeTypeDef time;
	  HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN);
	  int h=time.Hours, m=time.Minutes, s=time.Seconds;
	  printf("%i : %i : %i\n", h,m,s);
	  HAL_Delay(1000);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

 

No i teraz tak.

1. Ten kod z CubeMX działa bezbłędnie. Resetuję- zaczyna się wykonywać od nowa. Odcinam zasilanie (przez port USB) i podłączam ponownie- też działa.

2. Z kodem, który pisałem w samym Workbenchu jest natomiast tak, że zadziałał po raz pierwszy po wcześniejszym wgraniu programu 1. ^^ Resetuję przyciskiem- też wszystko było dobrze i program wykonywał się od początku. Natomiast, gdy wyłączę zasilanie i włączę to od nowa to samo- HAL_RTC_STATE_ERROR i godzina 00:00:00 😞 Jak próbowałem debuggować to wydaje mi się, że problem jest w funkcji HAL_RTC_Init, gdy wywoływana jest funkcja HAL_RTC_WaitForSynchro(hrtc).

Czy ktoś bardziej obeznany mógłby rzucić okiem? Może dla kogoś będzie oczywiste co ja tu zepsułem, a ja tymczasem siadam do kolejnych prób. Widzę, że w tych kodach zapomniałem dodać funkcji "lcd_draw_time", ale już nie będę wydłużać tego postu... Jak mówiłem z wyświetlaczem nie ma kłopotów i działa dobrze.

PS: Uprzedzę niektóre możliwe odpowiedzi w stylu "jak wspaniały i wygodny jest CubeMX, po co ręcznie wystukiwać konfigurację" 😄 Temat założyłem z ciekawości, żeby dowiedzieć się co tutaj zrobiłem źle, że RTC nie działa jak należy 😕

Edytowano przez Bhoy67
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.