Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.
Obě strany předchozí revize Předchozí verze Následující verze | Předchozí verze | ||
2017:envi-logger [2018/01/22 04:51] Miroslav Waldecker [Software] |
2017:envi-logger [2018/01/22 06:23] (aktuální) Miroslav Waldecker [Záver] |
||
---|---|---|---|
Řádek 32: | Řádek 32: | ||
- Konfigurácia pinov | - Konfigurácia pinov | ||
- Konfigurácia hodinových domén | - Konfigurácia hodinových domén | ||
- | - Kofigurácia periférií a komunikácia s obvodmi k nim pripojenými | + | - Kofigurácia periférií a komunikácia |
- Správa displeja | - Správa displeja | ||
- Ukladanie údajov | - Ukladanie údajov | ||
+ | |||
+ | ===== Konfigurácia pinov ===== | ||
+ | |||
+ | Pre správnu činnosť periférií je dôležité nastavenie konfigurácií pinov. Každý pin procesora obsahuje multiplexor s privedenými signálmi s rôznych periférií. | ||
+ | <code c> | ||
+ | |||
+ | CLOCK_EnableClock(kCLOCK_PortC); | ||
+ | CLOCK_EnableClock(kCLOCK_PortB); | ||
+ | CLOCK_EnableClock(kCLOCK_PortE); | ||
+ | |||
+ | // Set UART | ||
+ | |||
+ | PORT_SetPinMux(PORTC, PIN14_IDX, kPORT_MuxAlt3); /* PORTB16 (pin 62) is configured as UART0_RX */ | ||
+ | PORT_SetPinMux(PORTC, PIN15_IDX, kPORT_MuxAlt3); /* PORTB17 (pin 63) is configured as UART0_TX */ | ||
+ | SIM->SCGC1 = (SIM->SCGC1 | SIM_SCGC1_UART4_MASK); | ||
+ | |||
+ | PORT_SetPinMux(PORTB, PIN20_IDX, kPORT_MuxAsGpio); // GPIO Heater TGS 4146 1->ON | ||
+ | PORT_SetPinMux(PORTB, PIN10_IDX, kPORT_MuxAsGpio); | ||
+ | | ||
+ | //Set SDHC interface | ||
+ | |||
+ | const port_pin_config_t porte0_pin1_config = { | ||
+ | kPORT_PullUp, /* Internal pull-up resistor is enabled */ | ||
+ | kPORT_FastSlewRate, /* Fast slew rate is configured */ | ||
+ | kPORT_PassiveFilterDisable, /* Passive filter is disabled */ | ||
+ | kPORT_OpenDrainDisable, /* Open drain is disabled */ | ||
+ | kPORT_HighDriveStrength, /* High drive strength is configured */ | ||
+ | kPORT_MuxAlt4, /* Pin is configured as SDHC0_D1 */ | ||
+ | kPORT_UnlockRegister /* Pin Control Register fields [15:0] are not locked */ | ||
+ | }; | ||
+ | PORT_SetPinConfig(PORTE, PIN0_IDX, &porte0_pin1_config); /* PORTE0 (pin 1) is configured as SDHC0_D1 */ | ||
+ | const port_pin_config_t porte1_pin2_config = { | ||
+ | kPORT_PullUp, /* Internal pull-up resistor is enabled */ | ||
+ | kPORT_FastSlewRate, /* Fast slew rate is configured */ | ||
+ | kPORT_PassiveFilterDisable, /* Passive filter is disabled */ | ||
+ | kPORT_OpenDrainDisable, /* Open drain is disabled */ | ||
+ | kPORT_HighDriveStrength, /* High drive strength is configured */ | ||
+ | kPORT_MuxAlt4, /* Pin is configured as SDHC0_D0 */ | ||
+ | kPORT_UnlockRegister /* Pin Control Register fields [15:0] are not locked */ | ||
+ | }; | ||
+ | PORT_SetPinConfig(PORTE, PIN1_IDX, &porte1_pin2_config); /* PORTE1 (pin 2) is configured as SDHC0_D0 */ | ||
+ | const port_pin_config_t porte2_pin3_config = { | ||
+ | kPORT_PullUp, /* Internal pull-up resistor is enabled */ | ||
+ | kPORT_FastSlewRate, /* Fast slew rate is configured */ | ||
+ | kPORT_PassiveFilterDisable, /* Passive filter is disabled */ | ||
+ | kPORT_OpenDrainDisable, /* Open drain is disabled */ | ||
+ | kPORT_HighDriveStrength, /* High drive strength is configured */ | ||
+ | kPORT_MuxAlt4, /* Pin is configured as SDHC0_DCLK */ | ||
+ | kPORT_UnlockRegister /* Pin Control Register fields [15:0] are not locked */ | ||
+ | }; | ||
+ | PORT_SetPinConfig(PORTE, PIN2_IDX, &porte2_pin3_config); /* PORTE2 (pin 3) is configured as SDHC0_DCLK */ | ||
+ | const port_pin_config_t porte3_pin4_config = { | ||
+ | kPORT_PullUp, /* Internal pull-up resistor is enabled */ | ||
+ | kPORT_FastSlewRate, /* Fast slew rate is configured */ | ||
+ | kPORT_PassiveFilterDisable, /* Passive filter is disabled */ | ||
+ | kPORT_OpenDrainDisable, /* Open drain is disabled */ | ||
+ | kPORT_HighDriveStrength, /* High drive strength is configured */ | ||
+ | kPORT_MuxAlt4, /* Pin is configured as SDHC0_CMD */ | ||
+ | kPORT_UnlockRegister /* Pin Control Register fields [15:0] are not locked */ | ||
+ | }; | ||
+ | PORT_SetPinConfig(PORTE, PIN3_IDX, &porte3_pin4_config); /* PORTE3 (pin 4) is configured as SDHC0_CMD */ | ||
+ | const port_pin_config_t porte4_pin5_config = { | ||
+ | kPORT_PullUp, /* Internal pull-up resistor is enabled */ | ||
+ | kPORT_FastSlewRate, /* Fast slew rate is configured */ | ||
+ | kPORT_PassiveFilterDisable, /* Passive filter is disabled */ | ||
+ | kPORT_OpenDrainDisable, /* Open drain is disabled */ | ||
+ | kPORT_HighDriveStrength, /* High drive strength is configured */ | ||
+ | kPORT_MuxAlt4, /* Pin is configured as SDHC0_D3 */ | ||
+ | kPORT_UnlockRegister /* Pin Control Register fields [15:0] are not locked */ | ||
+ | }; | ||
+ | PORT_SetPinConfig(PORTE, PIN4_IDX, &porte4_pin5_config); /* PORTE4 (pin 5) is configured as SDHC0_D3 */ | ||
+ | const port_pin_config_t porte5_pin6_config = { | ||
+ | kPORT_PullUp, /* Internal pull-up resistor is enabled */ | ||
+ | kPORT_FastSlewRate, /* Fast slew rate is configured */ | ||
+ | kPORT_PassiveFilterDisable, /* Passive filter is disabled */ | ||
+ | kPORT_OpenDrainDisable, /* Open drain is disabled */ | ||
+ | kPORT_HighDriveStrength, /* High drive strength is configured */ | ||
+ | kPORT_MuxAlt4, /* Pin is configured as SDHC0_D2 */ | ||
+ | kPORT_UnlockRegister /* Pin Control Register fields [15:0] are not locked */ | ||
+ | }; | ||
+ | PORT_SetPinConfig(PORTE, PIN5_IDX, &porte5_pin6_config); /* PORTE5 (pin 6) is configured as SDHC0_D2 */ | ||
+ | const port_pin_config_t porte6_pin7_config = { | ||
+ | kPORT_PullDown, /* Internal pull-down resistor is enabled */ | ||
+ | kPORT_FastSlewRate, /* Fast slew rate is configured */ | ||
+ | kPORT_PassiveFilterDisable, /* Passive filter is disabled */ | ||
+ | kPORT_OpenDrainDisable, /* Open drain is disabled */ | ||
+ | kPORT_LowDriveStrength, /* Low drive strength is configured */ | ||
+ | kPORT_MuxAsGpio, /* Pin is configured as PTE6 */ | ||
+ | kPORT_UnlockRegister /* Pin Control Register fields [15:0] are not locked */ | ||
+ | }; | ||
+ | PORT_SetPinConfig(PORTE, PIN6_IDX, &porte6_pin7_config); /* PORTE6 (pin 7) is configured as PTE6 */ | ||
+ | } | ||
+ | |||
+ | void BOARD_I2C_ConfigurePins(void) { | ||
+ | CLOCK_EnableClock(kCLOCK_PortE); /* Port E Clock Gate Control: Clock enabled */ | ||
+ | |||
+ | //Set IIC | ||
+ | const port_pin_config_t porte24_pin31_config = { | ||
+ | kPORT_PullUp, /* Internal pull-up resistor is enabled */ | ||
+ | kPORT_FastSlewRate, /* Fast slew rate is configured */ | ||
+ | kPORT_PassiveFilterDisable, /* Passive filter is disabled */ | ||
+ | kPORT_OpenDrainEnable, /* Open drain is enabled */ | ||
+ | kPORT_LowDriveStrength, /* Low drive strength is configured */ | ||
+ | kPORT_MuxAlt5, /* Pin is configured as I2C0_SCL */ | ||
+ | kPORT_UnlockRegister /* Pin Control Register fields [15:0] are not locked */ | ||
+ | }; | ||
+ | PORT_SetPinConfig(PORTE, PIN24_IDX, &porte24_pin31_config); /* PORTE24 (pin 31) is configured as I2C0_SCL */ | ||
+ | const port_pin_config_t porte25_pin32_config = { | ||
+ | kPORT_PullUp, /* Internal pull-up resistor is enabled */ | ||
+ | kPORT_FastSlewRate, /* Fast slew rate is configured */ | ||
+ | kPORT_PassiveFilterDisable, /* Passive filter is disabled */ | ||
+ | kPORT_OpenDrainEnable, /* Open drain is enabled */ | ||
+ | kPORT_LowDriveStrength, /* Low drive strength is configured */ | ||
+ | kPORT_MuxAlt5, /* Pin is configured as I2C0_SDA */ | ||
+ | kPORT_UnlockRegister /* Pin Control Register fields [15:0] are not locked */ | ||
+ | }; | ||
+ | PORT_SetPinConfig(PORTE, PIN25_IDX, &porte25_pin32_config); /* PORTE25 (pin 32) is configured as I2C0_SDA */ | ||
+ | } | ||
+ | |||
+ | void BOARD_InitFlexbus(void){ | ||
+ | CLOCK_EnableClock(kCLOCK_PortB); /* Port B Clock Gate Control: Clock enabled */ | ||
+ | CLOCK_EnableClock(kCLOCK_PortC); /* Port C Clock Gate Control: Clock enabled */ | ||
+ | CLOCK_EnableClock(kCLOCK_PortD); /* Port D Clock Gate Control: Clock enabled */ | ||
+ | // Set Flexbus | ||
+ | PORT_SetPinMux(PORTD, PIN6_IDX, kPORT_MuxAlt5); /* PORTD6 (pin A2) is configured as FB_AD0 */ | ||
+ | PORT_SetPinMux(PORTD, PIN5_IDX, kPORT_MuxAlt5); /* PORTD5 (pin A3) is configured as FB_AD1 */ | ||
+ | PORT_SetPinMux(PORTD, PIN4_IDX, kPORT_MuxAlt5); /* PORTD4 (pin A4) is configured as FB_AD2 */ | ||
+ | PORT_SetPinMux(PORTD, PIN3_IDX, kPORT_MuxAlt5); /* PORTD3 (pin B4) is configured as FB_AD3 */ | ||
+ | PORT_SetPinMux(PORTD, PIN2_IDX, kPORT_MuxAlt5); /* PORTD2 (pin C4) is configured as FB_AD4 */ | ||
+ | PORT_SetPinMux(PORTC, PIN10_IDX, kPORT_MuxAlt5); /* PORTC10 (pin C7) is configured as FB_AD5 */ | ||
+ | PORT_SetPinMux(PORTC, PIN9_IDX, kPORT_MuxAlt5); /* PORTC9 (pin D7) is configured as FB_AD6 */ | ||
+ | PORT_SetPinMux(PORTC, PIN8_IDX, kPORT_MuxAlt5); /* PORTC8 (pin A8) is configured as FB_AD7 */ | ||
+ | PORT_SetPinMux(PORTC, PIN7_IDX, kPORT_MuxAlt5); /* PORTC7 (pin B8) is configured as FB_AD8 */ | ||
+ | PORT_SetPinMux(PORTC, PIN6_IDX, kPORT_MuxAlt5); /* PORTC6 (pin C8) is configured as FB_AD9 */ | ||
+ | PORT_SetPinMux(PORTC, PIN5_IDX, kPORT_MuxAlt5); /* PORTC5 (pin D8) is configured as FB_AD10 */ | ||
+ | PORT_SetPinMux(PORTC, PIN4_IDX, kPORT_MuxAlt5); /* PORTC4 (pin A9) is configured as FB_AD11 */ | ||
+ | PORT_SetPinMux(PORTC, PIN2_IDX, kPORT_MuxAlt5); /* PORTC2 (pin A12) is configured as FB_AD12 */ | ||
+ | PORT_SetPinMux(PORTC, PIN1_IDX, kPORT_MuxAlt5); /* PORTC1 (pin B11) is configured as FB_AD13 */ | ||
+ | PORT_SetPinMux(PORTC, PIN0_IDX, kPORT_MuxAlt5); /* PORTC0 (pin B12) is configured as FB_AD14 */ | ||
+ | PORT_SetPinMux(PORTB, PIN18_IDX, kPORT_MuxAlt5); /* PORTB18 (pin D12) is configured as FB_AD15 */ | ||
+ | PORT_SetPinMux(PORTB, PIN17_IDX, kPORT_MuxAlt5); /* PORTB17 (pin E9) is configured as FB_AD16 */ | ||
+ | |||
+ | PORT_SetPinMux(PORTC, PIN11_IDX, kPORT_MuxAlt5); /* PORTC11 (pin B7) is configured as FB_RW_b */ | ||
+ | PORT_SetPinMux(PORTB, PIN19_IDX, kPORT_MuxAlt5); /* PORTB19 (pin D11) is configured as FB_OE_b */ | ||
+ | PORT_SetPinMux(PORTC, PIN3_IDX, kPORT_MuxAlt5); /* PORTC3 (pin A11) is configured as FB_CLKOUT */ | ||
+ | PORT_SetPinMux(PORTD, PIN1_IDX, kPORT_MuxAlt5); /* PORTD1 (pin D4) is configured as FB_CS0_b */ | ||
+ | } | ||
+ | | ||
+ | </code> | ||
+ | |||
+ | ===== Konfigurácia hodín ===== | ||
+ | |||
+ | Ďalšou z esenciálnych konfigurácií, je nastavenie hodín pre periférie. Hlavným zdrojom je oscilátor v periférii pre fyzickú vrstvu ethernetu 50MHz. Z nej potom PLL blokom generujem hodiny pre jadro 120MHz, pre pamäť 60MHz, Flexbus (Vzhľadom na obmedzenie SSD1289 radiča 25MHz) 15MHz. | ||
+ | Zdrojom hodín pre RTC časovač a prevodník snímača tlaku je použitý oscilátor s kryštálom 32,768kHz. Ten funguje aj po vypnutá napájania. Výstup z neho je smerovaný na výstupný pin procesora CLKOUT. | ||
+ | |||
+ | ===== Kofigurácia periférií a komunikácia ===== | ||
+ | ==== TGS4161 a ADC ==== | ||
+ | |||
+ | Pre zber údajov zo senzoru koncentrácie j epoužitý interný prevodník ADC v single ended móde a internou referenciou. Funkcia pre nastavenie periférií: | ||
+ | |||
+ | <code c> | ||
+ | void Init_CO(void) { | ||
+ | //Set GPIO for heater control | ||
+ | gpio_pin_config_t heater = { kGPIO_DigitalOutput, 0, }; | ||
+ | GPIO_PinInit(GPIOB, 20U, &heater); | ||
+ | //Get ADC default config | ||
+ | ADC16_GetDefaultConfig(&adc16ConfigStruct); | ||
+ | |||
+ | adc16ConfigStruct.resolution = kADC16_ResolutionSE16Bit; | ||
+ | ADC16_Init(DEMO_ADC16_BASE, &adc16ConfigStruct); | ||
+ | ADC16_EnableHardwareTrigger(DEMO_ADC16_BASE, false); | ||
+ | if (kStatus_Success == ADC16_DoAutoCalibration(DEMO_ADC16_BASE)) { | ||
+ | PRINTF("ADC16_DoAutoCalibration() Done.\r\n"); | ||
+ | } else { | ||
+ | PRINTF("ADC16_DoAutoCalibration() Failed.\r\n"); | ||
+ | } | ||
+ | |||
+ | adc16ChannelConfigStruct.channelNumber = DEMO_ADC16_USER_CHANNEL; | ||
+ | adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false; | ||
+ | } | ||
+ | //Set heater on | ||
+ | void Start_sensor(void) { | ||
+ | GPIO_SetPinsOutput(GPIOB, 1U << 20U); | ||
+ | } | ||
+ | //Reset heater | ||
+ | void Stop_sensor(void) { | ||
+ | GPIO_ClearPinsOutput(GPIOB, 1U << 20U); | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | Funkcia pre čitanie vzorky vzčítanej prevodníkom - ADC0 kanál 0 single ended: | ||
+ | <code c> | ||
+ | int32_t get_adc(void) { | ||
+ | |||
+ | ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, | ||
+ | &adc16ChannelConfigStruct); | ||
+ | while (0U | ||
+ | == (kADC16_ChannelConversionDoneFlag | ||
+ | & ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE, | ||
+ | DEMO_ADC16_CHANNEL_GROUP))) | ||
+ | ; | ||
+ | return (ADC16_GetChannelConversionValue(DEMO_ADC16_BASE, | ||
+ | DEMO_ADC16_CHANNEL_GROUP)); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Prepočet hodnoty zmeranej AD prevodníkom na koncentráciu ppm CO2: | ||
+ | <code c> | ||
+ | int32_t get_concentration(void){ | ||
+ | float adc_mv; | ||
+ | float sens_mv; | ||
+ | float adc_mv_min; | ||
+ | float sens_mv_min; | ||
+ | float delta_emf; | ||
+ | int32_t co2ppm; | ||
+ | |||
+ | //Prepocet na rozsah + kalibracia | ||
+ | adc_mv_min = 5.03321924e-5 * (float)adc_val_min; | ||
+ | adc_mv = 5.03321924e-5 * (float)get_adc(); | ||
+ | //Prepocet prevodová charakteristika | ||
+ | sens_mv_min = (0.39 - 0.2*adc_mv_min)*1000.0; | ||
+ | sens_mv = (0.39 - 0.2*adc_mv)*1000.0; | ||
+ | //Prepocet na ppm zo semilox charakteristiky v datasheet-e | ||
+ | delta_emf = sens_mv_min - sens_mv; | ||
+ | sens_mv = powf(10.0,(0.0161*delta_emf + 2.5441)); | ||
+ | |||
+ | co2ppm = (int32_t)sens_mv; | ||
+ | return(co2ppm); | ||
+ | |||
+ | } | ||
+ | </code> | ||
+ | |||
+ | ==== SHT21, HP03M a ADC ==== | ||
+ | |||
+ | Nastavenie IIC periférie a GPIO pre ovládanie XCLR - reset signálu pre HP03M. | ||
+ | <code c> | ||
+ | void Init_iic(void) { | ||
+ | BOARD_I2C_ConfigurePins(); | ||
+ | gpio_pin_config_t xclr = { kGPIO_DigitalOutput, 0, }; | ||
+ | GPIO_PinInit(GPIOB, 10U, &xclr); | ||
+ | |||
+ | I2C_MasterGetDefaultConfig(&masterConfig); | ||
+ | masterConfig.baudRate_Bps = I2C_BAUDRATE; | ||
+ | |||
+ | sourceClock = I2C_MASTER_CLK_FREQ; | ||
+ | |||
+ | I2C_MasterInit(I2C0, &masterConfig, sourceClock); | ||
+ | |||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Komunikácia s SHT21. Funkcie pre čítanie teploty a vlhkosti a ich prepočet na °C a %RH: | ||
+ | <code c> | ||
+ | float read_temp() { | ||
+ | |||
+ | uint8_t data[5]; | ||
+ | uint16_t itemp; | ||
+ | float ftemp; | ||
+ | |||
+ | data[0] = (uint8_t) SHT21_TRIG_TEMP_HM; | ||
+ | while (kStatus_Success | ||
+ | != I2C_MasterStart(I2C0, SHT21_I2C_ADDRESS, kI2C_Write)) | ||
+ | ; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterWriteBlocking(I2C0, data, 1, kI2C_TransferNoStopFlag)) | ||
+ | ; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterRepeatedStart(I2C0, SHT21_I2C_ADDRESS, kI2C_Read)) | ||
+ | ; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterReadBlocking(I2C0, data, 3, kI2C_TransferCompleteFlag)) | ||
+ | ; | ||
+ | itemp = data[0]; | ||
+ | itemp = itemp << 8; | ||
+ | itemp |= data[1]; | ||
+ | itemp &= 0xFFFC; | ||
+ | ftemp = -48.85 + (175.72 * ((float) itemp)) / 65536.0; | ||
+ | |||
+ | return (ftemp); | ||
+ | } | ||
+ | |||
+ | float read_hum() { | ||
+ | |||
+ | uint8_t data[5]; | ||
+ | uint16_t ihum; | ||
+ | float fhum; | ||
+ | |||
+ | data[0] = (uint8_t) SHT21_TRIG_HUMIDITY_HM; | ||
+ | while (kStatus_Success | ||
+ | != I2C_MasterStart(I2C0, SHT21_I2C_ADDRESS, kI2C_Write)) | ||
+ | ; | ||
+ | while (kStatus_Success | ||
+ | != I2C_MasterWriteBlocking(I2C0, data, 1, kI2C_TransferNoStopFlag)) | ||
+ | ; | ||
+ | while (kStatus_Success | ||
+ | != I2C_MasterRepeatedStart(I2C0, SHT21_I2C_ADDRESS, kI2C_Read)) | ||
+ | ; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterReadBlocking(I2C0, data, 3, kI2C_TransferCompleteFlag)) | ||
+ | ; | ||
+ | ihum = data[0]; | ||
+ | ihum = ihum << 8; | ||
+ | ihum |= data[1]; | ||
+ | ihum &= 0xFFFC; | ||
+ | fhum = -6.0 + 125.0 * ((float) ihum) / 65536.0; | ||
+ | return (fhum); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Komunikácia s HP03M a výpočet barometrického tlaku, je zaujímavé, že tento senzor obsahuje 2 obvody, v jednom sú kalibračné a kompenzačné údaje, druhý je AD prevodník s meraním teploty pre kompenzáciu a tlaku. Každý z týchto obvodov má inú adresu a iný spôsob ich čítania: | ||
+ | |||
+ | <code c> | ||
+ | float read_pressure() { | ||
+ | |||
+ | uint8_t eeprom_data[18]; | ||
+ | uint16_t iPressure; | ||
+ | uint16_t iTemperature; | ||
+ | uint8_t data_index; | ||
+ | uint16_t C[7]; | ||
+ | uint8_t coef_A; | ||
+ | uint8_t coef_B; | ||
+ | uint8_t coef_C; | ||
+ | uint8_t coef_D; | ||
+ | float fTemp; | ||
+ | float fPressure; | ||
+ | float dut; | ||
+ | float offset; | ||
+ | float sensitivity; | ||
+ | float xpress; | ||
+ | |||
+ | GPIO_PinWrite(GPIOB, 10U, 1); | ||
+ | |||
+ | |||
+ | eeprom_data[0] = 0x10; | ||
+ | |||
+ | while (kStatus_Success != I2C_MasterStop(I2C0)) | ||
+ | ; | ||
+ | |||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterStart(I2C0, HP03_I2C_EEPROM_ADDRESS, kI2C_Write)) | ||
+ | ; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterWriteBlocking(I2C0, eeprom_data, 1, | ||
+ | kI2C_TransferNoStopFlag)) | ||
+ | ; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterRepeatedStart(I2C0, HP03_I2C_EEPROM_ADDRESS, kI2C_Read)) | ||
+ | ; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterReadBlocking(I2C0, eeprom_data, 18, | ||
+ | kI2C_TransferCompleteFlag)) | ||
+ | ; | ||
+ | |||
+ | for (data_index = 0; data_index <= 6; data_index++) { | ||
+ | C[data_index] = eeprom_data[data_index * 2]; | ||
+ | C[data_index] = C[data_index] << 8; | ||
+ | C[data_index] |= eeprom_data[(data_index * 2) + 1]; | ||
+ | } | ||
+ | |||
+ | coef_A = eeprom_data[14]; | ||
+ | coef_B = eeprom_data[15]; | ||
+ | coef_C = eeprom_data[16]; | ||
+ | coef_D = eeprom_data[17]; | ||
+ | |||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Write)) | ||
+ | ; | ||
+ | |||
+ | eeprom_data[0] = 0xFF; | ||
+ | eeprom_data[1] = 0xF0; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterWriteBlocking(I2C0, eeprom_data, 2, | ||
+ | kI2C_TransferCompleteFlag)) | ||
+ | ; | ||
+ | |||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Write)) | ||
+ | ; | ||
+ | eeprom_data[0] = 0xFD; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterWriteBlocking(I2C0, eeprom_data, 1, | ||
+ | kI2C_TransferNoStopFlag)) | ||
+ | ; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterRepeatedStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Read)) | ||
+ | ; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterReadBlocking(I2C0, eeprom_data, 2, | ||
+ | kI2C_TransferCompleteFlag)) | ||
+ | ; | ||
+ | |||
+ | iPressure = eeprom_data[0]; | ||
+ | iPressure = iPressure << 8; | ||
+ | iPressure |= eeprom_data[1]; | ||
+ | |||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Write)) | ||
+ | ; | ||
+ | |||
+ | eeprom_data[0] = 0xFF; | ||
+ | eeprom_data[1] = 0xE8; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterWriteBlocking(I2C0, eeprom_data, 2, | ||
+ | kI2C_TransferCompleteFlag)) | ||
+ | ; | ||
+ | |||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Write)) | ||
+ | ; | ||
+ | eeprom_data[0] = 0xFD; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterWriteBlocking(I2C0, eeprom_data, 1, | ||
+ | kI2C_TransferNoStopFlag)) | ||
+ | ; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterRepeatedStart(I2C0, HP03_I2C_AD_ADDRESS, kI2C_Read)) | ||
+ | ; | ||
+ | |||
+ | while (kStatus_Success | ||
+ | != I2C_MasterReadBlocking(I2C0, eeprom_data, 2, | ||
+ | kI2C_TransferCompleteFlag)) | ||
+ | ; | ||
+ | |||
+ | iTemperature = eeprom_data[0]; | ||
+ | iTemperature = iTemperature << 8; | ||
+ | iTemperature |= eeprom_data[1]; | ||
+ | GPIO_PinWrite(GPIOB, 10U, 0); | ||
+ | |||
+ | fTemp = (float)iTemperature; | ||
+ | |||
+ | if(iTemperature >= C[4]){ | ||
+ | dut = fTemp - (float)C[4] - ((fTemp-(float)C[4])/128.0) * ((fTemp-(float)C[4])/128.0) * (float)coef_A / (float)(2^coef_C); | ||
+ | }else{ | ||
+ | dut = fTemp - (float)C[4] - ((fTemp-(float)C[4])/128.0) * ((fTemp-(float)C[4])/128.0) * (float)coef_B / (float)(2^coef_C); | ||
+ | } | ||
+ | |||
+ | offset = ((float)C[1]+((float)C[3]-1024.0)*dut/16384.0)*4.0; | ||
+ | sensitivity = (float)C[0]+ (float)C[2]*dut/1024.0; | ||
+ | xpress = sensitivity * ((float)iPressure-7168.0)/16384.0 - offset; | ||
+ | fPressure = xpress*10.0/32.0+(float)C[6] + 253.0; | ||
+ | return (fPressure/10.0); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | ==== TFT display a FlexBus ==== | ||
+ | |||
+ | Pre riadenie TFT display-u som využil hotovú knižnicu: | ||
+ | https://www.element14.com/community/groups/development-tools/blog/2012/05/26/stm32f4-discovery-hy32d-tft-lcd Tú som však musel naportovať pre K64 procesor a zbernicu FluxBus: | ||
+ | Inicializácia: | ||
+ | <code c> | ||
+ | void Init_FlexBus(void){ | ||
+ | flexbus_config_t flexbusUserConfig; | ||
+ | |||
+ | FLEXBUS_GetDefaultConfig(&flexbusUserConfig); | ||
+ | |||
+ | flexbusUserConfig.waitStates = 2U; | ||
+ | flexbusUserConfig.portSize = kFLEXBUS_2Bytes; | ||
+ | flexbusUserConfig.chipBaseAddress = (uint32_t)TFT_DC_ADDRESS; | ||
+ | flexbusUserConfig.chipBaseAddressMask = 1U; | ||
+ | flexbusUserConfig.byteLaneShift = kFLEXBUS_Shifted; | ||
+ | flexbusUserConfig.autoAcknowledge = true; | ||
+ | |||
+ | FLEXBUS_Init(FB, &flexbusUserConfig); | ||
+ | } | ||
+ | </code> | ||
+ | Zápis dát do pamäte a do registrov: | ||
+ | <code c> | ||
+ | void vfnSendDataWord(unsigned short value) | ||
+ | { | ||
+ | *((unsigned short*)TFT_BASE_ADDRESS) = value; | ||
+ | } | ||
+ | |||
+ | void vfnSendCmdWord(unsigned short cmd) | ||
+ | { | ||
+ | *((unsigned short*)TFT_DC_ADDRESS) = cmd; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | ==== RTC ==== | ||
+ | |||
+ | Inicializácia a nastavenie hodín reálneho času: | ||
+ | <code c> | ||
+ | void Init_rtc(void){ | ||
+ | |||
+ | rtc_config_t rtcConfig; | ||
+ | |||
+ | RTC_GetDefaultConfig(&rtcConfig); | ||
+ | RTC_Init(RTC, &rtcConfig); | ||
+ | /* Select RTC clock source */ | ||
+ | RTC_SetClockSource(RTC); | ||
+ | } | ||
+ | |||
+ | void rtc_settime(rtc_datetime_t date){ | ||
+ | |||
+ | RTC_StopTimer(RTC); | ||
+ | RTC_SetDatetime(RTC, &date); | ||
+ | RTC_StartTimer(RTC); | ||
+ | } | ||
+ | |||
+ | rtc_datetime_t rtc_gettime(void){ | ||
+ | |||
+ | rtc_datetime_t date; | ||
+ | |||
+ | RTC_GetDatetime(RTC, &date); | ||
+ | return(date); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | ==== Hlavná slučka a Fat FS ==== | ||
+ | Kinetis software development kit obsahuje okrem štandardných ovládačov periférií aj middleware pre prácu s USB a SD kartami s podporou Fat FS, ktorý som použil. Tým, že zapisujem namerané údaje v textovom formáte, tieto sú po pripojeni SD karty do počítača bezproblémov spracovateľné. V hlavnej slučke sa periodicky vyčítavajú údaje, ktoré sa okamžite zobrazujú na display-i a každých 10s sa otvorí súbor pre zápis a udaje sa zapíšu vo formáte dátum, čas, koncentrácia CO2, teplota, vlhkosť a tlak. Po zápise sa súbor okamžite uzavrie. | ||
+ | <code c> | ||
+ | while (1) { | ||
+ | |||
+ | date = rtc_gettime(); | ||
+ | sprintf(str, "%02hd-%02hd-%04hd %02hd:%02hd:%02hd ", date.day, | ||
+ | date.month, date.year, date.hour, date.minute, date.second); | ||
+ | |||
+ | LCD_SetTextColor(ASSEMBLE_RGB(0, 0, 0)); | ||
+ | LCD_CharSize(16); | ||
+ | LCD_StringLine(1, 1, (uint8_t*) str); | ||
+ | co_value = get_concentration(); | ||
+ | sprintf(str, "CO2:%d ppm", co_value); | ||
+ | LCD_SetTextColor(ASSEMBLE_RGB(0, 0, 0xFF)); | ||
+ | LCD_CharSize(24); | ||
+ | LCD_StringLine(1, 16, (uint8_t*) str); | ||
+ | |||
+ | temperature = read_temp(); | ||
+ | humidity = read_hum(); | ||
+ | LCD_SetTextColor(ASSEMBLE_RGB(0xFF, 0, 0)); | ||
+ | sprintf(str, "T: %2.2f C", temperature); | ||
+ | LCD_StringLine(1, 40, (uint8_t*) str); | ||
+ | LCD_SetTextColor(ASSEMBLE_RGB(0, 0, 0xFF)); | ||
+ | sprintf(str, "RH: %2.2f %%", humidity); | ||
+ | LCD_StringLine(1, 64, (uint8_t*) str); | ||
+ | LCD_SetTextColor(ASSEMBLE_RGB(0xFF, 0, 0)); | ||
+ | pressure = read_pressure(); | ||
+ | sprintf(str, "P:%6.2fhPa", pressure); | ||
+ | LCD_StringLine(1, 88, (uint8_t*) str); | ||
+ | Delay(10); | ||
+ | |||
+ | if(card_ok && prev_second != date.second && !(date.second % 10)){ | ||
+ | sprintf(g_bufferWrite, "%02hd-%02hd-%04hd %02hd:%02hd:%02hd %d %2.2f %2.2f %6.2f \r\n", date.day, | ||
+ | date.month, date.year, date.hour, date.minute, date.second, co_value, temperature, humidity, pressure); | ||
+ | f_open(&g_fileObject, _T("/data.dat"), (FA_WRITE | FA_READ | FA_OPEN_APPEND)); | ||
+ | |||
+ | error = f_write(&g_fileObject, g_bufferWrite, strlen(g_bufferWrite), &bytesWritten); | ||
+ | f_close(&g_fileObject); | ||
+ | prev_second = date.second; | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | ===== Video datalogger ===== | ||
+ | {{youtube>R_bAfAzXU1A?medium}} | ||
+ | |||
+ | ===== Výpis dát ===== | ||
+ | V tomto bolku je príklad zmeraných dát, potom ako som začal vetrať. Je vidieť, ako klesá koncentrácia CO2, ale zároveň aj s teplotou... | ||
+ | |||
+ | <file> | ||
+ | 14-01-2018 17:20:10 1052 21.98 27.91 1017.92 | ||
+ | 14-01-2018 17:20:20 1021 21.99 27.36 1017.80 | ||
+ | 14-01-2018 17:20:30 971 21.93 26.92 1017.80 | ||
+ | 14-01-2018 17:20:40 955 21.92 26.60 1017.67 | ||
+ | 14-01-2018 17:20:50 939 21.87 25.60 1017.90 | ||
+ | 14-01-2018 17:21:00 920 21.83 24.97 1017.95 | ||
+ | 14-01-2018 17:21:10 909 21.79 24.63 1017.90 | ||
+ | 14-01-2018 17:21:20 884 21.73 24.27 1017.90 | ||
+ | 14-01-2018 17:21:30 898 21.64 24.33 1017.95 | ||
+ | 14-01-2018 17:21:40 883 21.58 23.90 1017.99 | ||
+ | 14-01-2018 17:21:50 917 21.50 24.53 1017.89 | ||
+ | 14-01-2018 17:22:00 905 21.41 24.16 1018.08 | ||
+ | 14-01-2018 17:22:10 872 21.35 23.40 1017.94 | ||
+ | 14-01-2018 17:22:20 862 21.24 23.51 1017.98 | ||
+ | 14-01-2018 17:22:30 909 21.13 23.87 1017.94 | ||
+ | 14-01-2018 17:22:40 861 21.13 22.79 1017.95 | ||
+ | 14-01-2018 17:22:50 833 21.12 22.56 1017.95 | ||
+ | 14-01-2018 17:23:00 841 21.11 22.62 1018.04 | ||
+ | 14-01-2018 17:23:10 821 21.02 22.26 1017.94 | ||
+ | 14-01-2018 17:23:20 814 20.96 22.06 1018.06 | ||
+ | 14-01-2018 17:23:30 803 20.91 21.89 1018.05 | ||
+ | 14-01-2018 17:23:40 819 20.86 21.93 1017.82 | ||
+ | 14-01-2018 17:23:50 864 20.76 23.28 1018.07 | ||
+ | 14-01-2018 17:24:00 841 20.71 22.27 1017.97 | ||
+ | 14-01-2018 17:24:10 799 20.64 21.51 1018.00 | ||
+ | 14-01-2018 17:24:20 794 20.58 21.94 1018.07 | ||
+ | </file> | ||
+ | |||
+ | |||
+ | ==== Záver ==== | ||
+ | |||
+ | Tento projekt je prototyp, na ktorom som si overil rôzne senzory, vyskúšal som prostredie MCUXpresso firmy NXP a ich software-ové knižnice pre prácu s ARM procesormi Kinetis KSDK verzie 2.3. K tomu, aby to bol plnohodnotný projekt je nutné prerobiť a dorobiť niekoľko vecí. Najmä radiče pre komunikáciu prerobiť z blokovacieho na neblokovací režim, veľa času stráca procesor tým, že čaká, kým periféria zmeria a odpovie. Ďalej je nutné prerobiť HW vývojovej dosky na zálohovanie z batérie pre kalibračné dáta a hodiny reálneho času. Takisto ovládanie z konzoly a prekopírovávanie uložených dát. Z užívateľského rozhrania je vhodné dorobiť grafické zobrazenie údajov v čase. Debug sériový port, ktorý je teraz použitý previesť na USB com port, a tento sériový port priviesť na malý WiFi modul so serverom, na ktorom budú prístupné namerané údaje z lokálnej siete. Za úvahu stojí aj zmena senzora koncentrácie CO2, keďže je to už pomerne obsolete senzor, ktorý je náchylný na všetky parametre ako napájacie napätie, ktoré v tomto prípade nie je vôbec stabilné, nepresnosť, stále je nutné ho kalibrovať a náročný prepočet. | ||
+ | |||
+ | Zdroje:{{ :2017:xwalde01:envilogger.rar | Zdrojové súbory}} | ||
+ | |||