Digilent Pmod i STM32 (cz. 8) – PmodMTDS, PmodRTCC i PmodCMPS2
PmodRTCC
Drugi z prezentowanych w tej części modułów to PmodRTCC zawierający zegar czasu rzeczywistego z kalendarzem oparty o układ Microchip MCP79410. Układ ten umożliwia dodatkowo ustawienie dwóch alarmów, generację fali prostokątnej, a także korzystanie z pamięci EEPROM (128 B) i SRAM (64 B). Do obsługi modułu PmodRTCC została udostępniona biblioteka RTCCI2C dostępna na stronie producenta: https://reference.digilentinc.com/pmod/pmod/rtcc/example_code. Jest ona przeznaczona dla środowiska MPIDE, dlatego na potrzeby opisywanego przykładu musiała ona zostać modyfikowana tak, aby mogła być użyta w środowisku Atollic z mikrokontrolerem STM32L496ZGT6.
Połączenie z modułem KAmeleon
Moduł PmodRTCC posiada 8-pinowe złącze dla interfejsu I2C (J2) i 2-pinowe złącze J1 zawierające piny MFP (Multi-Function Pin), a także GND. Pin MFP może pełnić różne funkcje, zależnie od konfiguracji układu – w prezentowanym przykładzie będzie on źródłem przerwań wywołanych wystąpieniem alarmu. Sygnały modułu PmodRTCC podłączono do złącza oznaczonego jako ARDUINO CONNECTOR na płytce KAmeleon zgodnie z tabelą 4 i fotografią 5.
Tabela 4. Sposób podłączenia modułu PmodRTCC do złącza ARDUINO CONNECTOR zestawu KAmeleon
| Sygnał | Numer pinu PmodRTCC | Numer pinu KAmeleon ARDUINO CONNECTOR | Pin mikrokontrolera |
| SCL | 1 (J2) | D15 | PF14 |
| SDA | 2 (J2) | D14 | PF15 |
| MFP | 1 (J1) | D13 | PB10 |
Fotografia 5. Moduł PmodRTCC podłączony do płytki KAmeleon
Kod przykładu
Za obsługę interfejsu I2C odpowiadają trzy zmodyfikowane metody klasy RTCCI2C: begin, readValue i writeValue. Pierwsza z nich, przedstawiona na listingu 5, odpowiada za konfigurację interfejsu I2C4, a także pinu PB10 do obsługi przerwania. Przerwanie jest wykrywane na zboczu opadającym sygnału MFP w momencie wystąpienia alarmu. Dla komunikacji I2C konfigurowane są dwa piny – PF14 i PF15 oraz interfejs I2C4. Dla tego ostatniego konieczne jest podanie wartości rejestru TIMINGR, przedstawionego na rysunku 6. Jest on odpowiedzialny za generację odpowiednich przebiegów czasowych na liniach SDA i SCL: SCLL i SCLH definiują długość stanu niskiego i wysokiego sygnału SCL, SCLDEL oznacza opóźnienie pomiędzy ustawieniem wartości na linii danych a zboczem narastającym sygnału zegarowego, natomiast SDADEL opóźnienie pomiędzy zboczem opadającym zegara, a zmiana stanu na linii danych. Pole PRESC wyznacza dzielnik sygnału zegarowego taktującego układ I2C mikrokontrolera.
Listing 5. Konfiguracja interfejsu I2C do komunikacji z modułem PmodRTCC
void RTCCI2C::begin()
{
__HAL_RCC_I2C4_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Pin = GPIO_PIN_10;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C4;
GPIO_InitStruct.Pin = GPIO_PIN_14 | GPIO_PIN_15;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
this->i2c.Instance = I2C4;
this->i2c.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
this->i2c.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
this->i2c.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
this->i2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
this->i2c.Init.OwnAddress1 = 0x01;
this->i2c.Init.Timing = 0x10563046;
HAL_I2C_Init(&this->i2c);
}
Rysunek 6. Definicja rejestru I2C_TIMINGR (źródło: dokumentacja mikrokontrolera STM32L496ZG)
Funkcje odpowiedzialne za komunikację z modułem PmodRTCC przedstawiono na listingu 6. Wykorzystują one blokujące wywołania HAL_I2C_Master_Transmit i HAL_I2C_Master_Receive biblioteki STM32Cube.
Listing 6. Funkcje realizujące odczyt i zapis rejestru.
{
uint8_t value = 0;
HAL_I2C_Master_Transmit(&this->i2c, RTCC_I2C_ADDR, &address, 1, 100);
HAL_I2C_Master_Receive(&this->i2c, RTCC_I2C_ADDR, &value, 1, 100);
return value;
}
void RTCCI2C::writeValue(uint8_t address, uint8_t value)
{
uint8_t data[2] = {address, value};
HAL_I2C_Master_Transmit(&this->i2c, RTCC_I2C_ADDR, data, 2, 100);
}
Konfiguracja rejestrów MCP79410
Oprócz wymienionych funkcji, klasa RTCCI2C zawiera także metody konfigurujące poszczególne rejestry układu MCP79410. W tabeli 5 wymieniono funkcje użyte w kodzie przykładu. Wszystkie wartości są zapisywane i odczytywane w kodzie BCD.
Tabela 5. Metody klasy RTCCI2C użyte w przykładzie
| Metoda klasy RTCCI2C | Opis |
| startClock/stopClock | Uruchomienie/zatrzymanie zegara przez włączenie/wyłączenie oscylatora. |
| setSec/getSec | Zapis/odczyt sekund zegara lub alarmu. |
| setMin/getMin | Zapis/odczyt minut zegara lub alarmu. |
| setHour/getHour | Zapis/odczyt godziny zegara lub alarmu. |
| setDay/getDay | Zapis/odczyt dnia tygodnia (0x01 – 0x07) zegara lub alarmu. |
| setDate/getDate | Zapis/odczyt dnia miesiąca (0x01 – 0x32) zegara lub alarmu. |
| setMonth/getMonth | Zapis/odczyt miesiąca (0x01 – 0x12) zegara lub alarmu. |
| setYear/getYear | Zapis/odczyt roku (0x00 – 0x99) zegara lub alarmu. |
| enableAlarm | Włączenie alarmu |
| getAmPm | Czas dla zegara 12-godzinnego (AM/PM). |
Funkcja main
Funkcję main przykładowej aplikacji przedstawiono na listingu 7. Konfiguruje ona moduł PmodRTCC i ustawia datę: Niedziela, 4. marca 2018 23:15:30. Następnie ustawiany jest alarm na 10 sekund od zdefiniowanej daty. Pętla główna, za pomocą funkcji pomocniczej printTime, co sekundę odczytuje datę i godzinę. Odczytane wartości są od razu wysyłane na port szeregowy LPUART1. Alarm jest sygnalizowany przez zapalenie diody LED1 podłączonej do pinu PC7. Port szeregowy LPUART1 jest konfigurowany i obsługiwany za pomocą kodu znajdującego się w pliku serial.c, natomiast sterownik diody został umieszczony w pliku led.c.
Listing 7. Kod główny przykładowej aplikacji
int main(void)
{
HAL_Init();
SystemClock_Config();
Serial_Config();
Led_Config();
RTCCI2C myRTCC;
myRTCC.begin();
//set the real time clock
myRTCC.stopClock();
myRTCC.setSec(RTCC_RTCC, 0x30);
myRTCC.setMin(RTCC_RTCC, 0x15);
myRTCC.setHour(RTCC_RTCC, 0x11, RTCC_PM);
myRTCC.setDay(RTCC_RTCC, 0x07);
myRTCC.setDate(RTCC_RTCC, 0x04);
myRTCC.setMonth(RTCC_RTCC, 0x03);
myRTCC.setYear(0x18);
// Set the alarm for 10 seconds after written time.
myRTCC.setSec(RTCC_ALM0, 0x40);
myRTCC.setMin(RTCC_ALM0, 0x15);
myRTCC.setHour(RTCC_ALM0, 0x11, RTCC_PM);
myRTCC.setDay(RTCC_ALM0, 0x07);
myRTCC.setDate(RTCC_ALM0, 0x04);
myRTCC.setMonth(RTCC_ALM0, 0x03);
myRTCC.enableAlarm(RTCC_ALM0, RTCC_ALMC2 | RTCC_ALMC1 | RTCC_ALMC0);
myRTCC.startClock();
while(1) {
HAL_Delay(1000);
printTime(&myRTCC, RTCC_RTCC);
}
}


Technologie End of Life i bezpieczeństwo sieci – wyzwania Europy związane z tzw. długiem technologicznym
Najczęstsze błędy firm przy wyborze dostawcy energii i jak ich uniknąć
Fotorezystor, czyli czujnik światła dwojakiego działania. Przykład innowacji w automatyce i elektronice możliwej dzięki technologii fotooporników 



