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

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • 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.