diff --git a/Include/gps.h b/Include/gps.h new file mode 100644 --- /dev/null +++ b/Include/gps.h @@ -0,0 +1,44 @@ +#ifndef GPS_H_ +#define GPS_H_ + +#include + + +typedef struct _gps_data +{ + uint32_t pdop; + uint8_t sats_in_solution; + int32_t speed; + int32_t heading; + + int32_t latitude; + int32_t longitude; + int32_t altitude; + + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + + uint8_t valid; + uint8_t fixtype; + +} gps_data_t; + + +void gps_update_data(void); + +uint8_t gps_check_nav(void); + + +void gps_poweron(void); +void gps_poweroff(void); + +void gps_acquirefix(void); +uint8_t gps_getstate(void); + +gps_data_t* gps_getdata(void); +uint8_t gps_ison(void); + +#endif /* GPS_H_ */ diff --git a/Include/system/gpio.h b/Include/system/gpio.h --- a/Include/system/gpio.h +++ b/Include/system/gpio.h @@ -9,6 +9,10 @@ //////////////////////////////////// +#define GPS_NOTEN_PORT GPIOA +#define GPS_NOTEN_PIN GPIO_PIN_1 +#define GPS_NOTEN GPS_NOTEN_PORT , GPS_NOTEN_PIN + void gpio_init(void); void gpio_schedule_shutdown(void); diff --git a/Include/system/uart.h b/Include/system/uart.h new file mode 100644 --- /dev/null +++ b/Include/system/uart.h @@ -0,0 +1,12 @@ +#ifndef __usart_H +#define __usart_H + +#include "stm32f0xx_hal.h" + +void uart_init(void); +void uart_deinit(void); +UART_HandleTypeDef* uart_gethandle(void); +DMA_HandleTypeDef* uart_get_txdma_handle(void); +DMA_HandleTypeDef* uart_get_rxdma_handle(void); + +#endif diff --git a/Libraries/Si446x/si446x.c b/Libraries/Si446x/si446x.c --- a/Libraries/Si446x/si446x.c +++ b/Libraries/Si446x/si446x.c @@ -132,8 +132,6 @@ void si446x_init(void) HAL_Delay(10); si446x_cw_status = 0; - - si446x_cw_on(); } diff --git a/Libraries/aprs/aprs.c b/Libraries/aprs/aprs.c --- a/Libraries/aprs/aprs.c +++ b/Libraries/aprs/aprs.c @@ -25,6 +25,7 @@ #include "config.h" #include "aprs.h" +#include "gps.h" //#include "gps.h" //#include "adc.h" #include "ax25.h" @@ -56,8 +57,14 @@ void aprs_send(void) ax25_send_header(addresses, sizeof(addresses)/sizeof(addresses[0])); ax25_send_byte(','); + char tmpBuffer[128]; + tmpBuffer[0] = ','; + tmpBuffer[1] = '\0'; + //ax25_send_string(get_latitude()); - ax25_send_string("42.153749"); + snprintf(tmpBuffer, 128, "%g,", gps_getdata()->latitude / 10000000.0); + //ax25_send_string("42.153749"); + ax25_send_string(tmpBuffer); ax25_send_byte(','); //ax25_send_string(get_longitude()); ax25_send_string("53.234823"); @@ -80,6 +87,8 @@ void aprs_send(void) ax25_send_byte(','); //ax25_send_string(get_temperature()); + snprintf(tmpBuffer, 128, "%u,", gps_getdata()->pdop); + ax25_send_string(tmpBuffer); //ax25_send_string(get_hdop()); //ax25_send_byte(','); diff --git a/Source/gps.c b/Source/gps.c new file mode 100644 --- /dev/null +++ b/Source/gps.c @@ -0,0 +1,264 @@ +// +// GPS: communicate with ublox GPS module via ubx protocol +// + +#include "stm32f0xx_hal.h" + +#include "config.h" +#include "system/gpio.h" +#include "system/uart.h" +#include "gps.h" + + +volatile gps_data_t position; +uint8_t gpson = 0; + +// Private methods +static void gps_ubx_checksum(uint8_t* data, uint8_t len, uint8_t* cka, uint8_t* ckb); +static uint8_t _gps_verify_checksum(uint8_t* data, uint8_t len); + + +// Poll for fix data from the GPS and update the internal structure +void gps_update_data(void) +{ + // Error! + if(!gpson) + { +// led_blink(5); + return; + } + + // Construct the request to the GPS + uint8_t request[8] = {0xB5, 0x62, 0x01, 0x07, 0x00, 0x00, 0xFF, 0xFF}; + + + volatile uint8_t check_a = 0; + volatile uint8_t check_b = 0; + for(uint8_t i = 2; i<6; i++) + { + check_a += request[i]; + check_b += check_a; + } + request[6] = check_a; + request[7] = check_b; + + volatile uint8_t flushed = uart_gethandle()->Instance->RDR; + HAL_UART_Transmit(uart_gethandle(), request, 8, 100); + + + + // Get the message back from the GPS + uint8_t buf[100]; + for(uint8_t i=0; i<100; i++) + buf[i] = 0xaa; + volatile HAL_StatusTypeDef res = HAL_UART_Receive(uart_gethandle(), buf, 100, 3000); + + // Check 60 bytes minus SYNC and CHECKSUM (4 bytes) +// if( !_gps_verify_checksum(&buf[2], 96) ) +// led_blink(2); + + + //volatile uint32_t gpstime_ms = (buf[6+0] << 24) | (buf[6+1] << 16) | buf[6+2] << 8) | (buf[6+3]); + + position.month = buf[6+6]; + position.day = buf[6+7]; + position.hour = buf[6+8]; + position.minute = buf[6+9]; + position.second = buf[6+10]; + position.valid = buf[6+11] & 0b1111; + position.fixtype = buf[6+20]; + + position.sats_in_solution = buf[6+23]; + + position.longitude = (buf[6+24] << 0) | (buf[6+25] << 8) | (buf[6+26] << 16) | (buf[6+27] << 24); // degrees + position.latitude = (buf[6+28] << 0) | (buf[6+29] << 8) | (buf[6+30] << 16) | (buf[6+31] << 24); // degrees + + position.altitude = (buf[6+36] << 0) | (buf[6+37] << 8) | (buf[6+38] << 16) | (buf[6+39] << 24); // mm above sealevel + position.altitude /= 1000; // mm => m + + position.speed = (buf[6+60] << 0) | (buf[6+61] << 8) | (buf[6+62] << 16) | (buf[6+63] << 24); // mm/second + position.speed /= 1000; // mm/s -> m/s + + position.pdop = (buf[6+76] << 0) | (buf[6+77] << 8); + position.pdop /= 100; // scale to dop units + + position.heading = (buf[6+84] << 0) | (buf[6+85] << 8) | (buf[6+86] << 16) | (buf[6+87] << 24); // mm above sealevel + position.heading /= 100000; // 1e-5 + +// // Return the value if GPSfixOK is set in 'flags' +// if( buf[17] & 0x01 ) +// *lock = buf[16]; +// else +// *lock = 0; + +} + +// TODO: Add data valid flag: invalidate data when GPS powered off + + +// Verify that the uBlox 6 GPS receiver is set to the <1g airborne navigaion mode. +uint8_t gps_check_nav(void) +{ + uint8_t request[8] = {0xB5, 0x62, 0x06, 0x24, 0x00, 0x00, + 0x2A, 0x84}; + uint8_t flushed = uart_gethandle()->Instance->RDR; + HAL_UART_Transmit(uart_gethandle(), request, 8, 100); + + // Get the message back from the GPS + uint8_t buf[44]; + HAL_UART_Receive(uart_gethandle(), buf, 44, 100); + +// // Verify sync and header bytes +// if( buf[0] != 0xB5 || buf[1] != 0x62 ) +// led_set(LED_RED, 1); +// if( buf[2] != 0x06 || buf[3] != 0x24 ) +// led_set(LED_RED, 1); + + // Check 40 bytes of message checksum +// if( !_gps_verify_checksum(&buf[2], 40) ) led_set(LED_RED, 1); + + // Clock in and verify the ACK/NACK + uint8_t ack[10]; +// for(uint8_t i = 0; i < 10; i++) +// ack[i] = _gps_get_byte(); + + HAL_UART_Receive(uart_gethandle(), ack, 10, 100); + + // If we got a NACK, then return 0xFF + if( ack[3] == 0x00 ) return 0xFF; + + // Return the navigation mode and let the caller analyse it + return buf[8]; +} + + +// Verify the checksum for the given data and length. +static uint8_t _gps_verify_checksum(uint8_t* data, uint8_t len) +{ + uint8_t a, b; + gps_ubx_checksum(data, len, &a, &b); + if( a != *(data + len) || b != *(data + len + 1)) + return 0; + else + return 1; +} + + +// Calculate a UBX checksum using 8-bit Fletcher (RFC1145) +static void gps_ubx_checksum(uint8_t* data, uint8_t len, uint8_t* cka, uint8_t* ckb) +{ + *cka = 0; + *ckb = 0; + for( uint8_t i = 0; i < len; i++ ) + { + *cka += *data; + *ckb += *cka; + data++; + } +} + + +// Power on GPS module and initialize UART +void gps_poweron(void) +{ + // NOTE: pchannel + HAL_GPIO_WritePin(GPS_NOTEN, 0); + uart_init(); + + // Disable messages + uint8_t setGGA[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XFF, 0X23}; + HAL_UART_Transmit(uart_gethandle(), setGGA, sizeof(setGGA)/sizeof(uint8_t), 100); + HAL_Delay(100); + + uint8_t ackbuffer[10]; + for(uint8_t i=0; i<10; i++) + ackbuffer[i] = 0xaa; + HAL_UART_Receive(uart_gethandle(), ackbuffer, 10, 100); + + uint8_t setZDA[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X08, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X07, 0X5B}; + HAL_UART_Transmit(uart_gethandle(), setZDA, sizeof(setZDA)/sizeof(uint8_t), 100); + HAL_Delay(100); + + uint8_t setGLL[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X2A}; + HAL_UART_Transmit(uart_gethandle(), setGLL, sizeof(setGLL)/sizeof(uint8_t), 100); + HAL_Delay(100); + + uint8_t setGSA[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X02, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X01, 0X31}; + HAL_UART_Transmit(uart_gethandle(), setGSA, sizeof(setGSA)/sizeof(uint8_t), 100); + HAL_Delay(100); + + uint8_t setGSV[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X03, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X02, 0X38}; + HAL_UART_Transmit(uart_gethandle(), setGSV, sizeof(setGSV)/sizeof(uint8_t), 100); + HAL_Delay(100); + + uint8_t setRMC[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X03, 0X3F}; + HAL_UART_Transmit(uart_gethandle(), setRMC, sizeof(setRMC)/sizeof(uint8_t), 100); + HAL_Delay(100); + + uint8_t setVTG[] = {0XB5, 0X62, 0X06, 0X01, 0X08, 0X00, 0XF0, 0X05, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X46}; + HAL_UART_Transmit(uart_gethandle(), setVTG, sizeof(setRMC)/sizeof(uint8_t), 100); + HAL_Delay(100); + + +// // Disable GLONASS mode +// uint8_t disable_glonass[20] = {0xB5, 0x62, 0x06, 0x3E, 0x0C, 0x00, 0x00, 0x00, 0x20, 0x01, 0x06, 0x08, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x01, 0x8F, 0xB2}; +// +// //gps_sendubx(disable_glonass, 20); +// volatile HAL_StatusTypeDef res = HAL_UART_Transmit(uart_gethandle(), disable_glonass, 20, 100); +// +// // Enable power saving +// uint8_t enable_powersave[10] = {0xB5, 0x62, 0x06, 0x11, 0x02, 0x00, 0x08, 0x01, 0x22, 0x92}; +// //gps_sendubx(enable_powersave, 10); +// res = HAL_UART_Transmit(uart_gethandle(), enable_powersave, 10, 100); +// +// +// // Set dynamic model 6 (<1g airborne platform) +// uint8_t airborne_model[] = { 0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xDC }; +// //gps_sendubx(airborne_model, sizeof(airborne_model)/sizeof(uint8_t)); +// res = HAL_UART_Transmit(uart_gethandle(), airborne_model, sizeof(airborne_model)/sizeof(uint8_t), 100); + + + + + + // Begin DMA reception + //HAL_UART_Receive_DMA(uart_gethandle(), nmeaBuffer, NMEABUFFER_SIZE); + + gpson = 1; +} + + +// Power off GPS module +void gps_poweroff(void) +{ + // NOTE: pchannel +// position.hour = 0; +// position.minute = 0; +// position.second = 0; +// position.altitude = 0; +// position.latitude = 0; +// position.longitude = 0; +// position.day = 0; +// position.month = 0; +// position.fixtype = 0; +// position.valid = 0; + position.pdop = 0; + position.sats_in_solution = 0; +// position.speed = 0; + + uart_deinit(); + HAL_GPIO_WritePin(GPS_NOTEN, 1); + gpson = 0; +} + +gps_data_t* gps_getdata(void) +{ + return &position; +} + +uint8_t gps_ison(void) +{ + return gpson; +} + +// vim:softtabstop=4 shiftwidth=4 expandtab diff --git a/Source/main.c b/Source/main.c --- a/Source/main.c +++ b/Source/main.c @@ -8,10 +8,13 @@ #include "system/gpio.h" #include "system/sysclk.h" #include "system/watchdog.h" +#include "system/uart.h" #include "stm32f0xx_hal.h" #include "si446x/si446x.h" #include "aprs/aprs.h" #include "aprs/afsk.h" +#include "gps.h" + int main(void) { @@ -19,8 +22,11 @@ int main(void) sysclock_init(); gpio_init(); + afsk_init(); si446x_init(); + gps_poweron(); + // Software timers uint32_t last_led = HAL_GetTick(); @@ -29,6 +35,7 @@ int main(void) // Blink LEDs if(HAL_GetTick() - last_led > 1500) { + gps_update_data(); aprs_send(); while(afsk_busy()); diff --git a/Source/system/gpio.c b/Source/system/gpio.c --- a/Source/system/gpio.c +++ b/Source/system/gpio.c @@ -30,6 +30,13 @@ void gpio_init(void) GPIO_InitStruct.Speed = GPIO_SPEED_LOW; HAL_GPIO_Init(PORT_LED_POWER, &GPIO_InitStruct); + GPIO_InitStruct.Pin = GPS_NOTEN_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_LOW; + HAL_GPIO_Init(GPS_NOTEN_PORT, &GPIO_InitStruct); + HAL_GPIO_WritePin(GPS_NOTEN, 1); // yes, keep the chip disabled + // Toggle the power LED HAL_GPIO_TogglePin(LED_POWER); diff --git a/Source/system/uart.c b/Source/system/uart.c new file mode 100644 --- /dev/null +++ b/Source/system/uart.c @@ -0,0 +1,115 @@ +#include "stm32f0xx_hal.h" + +#include "system/uart.h" +#include "config.h" +#include "system/gpio.h" + +UART_HandleTypeDef huart1; +DMA_HandleTypeDef hdma_usart1_rx; +DMA_HandleTypeDef hdma_usart1_tx; +uint8_t uart_initted = 0; + +void uart_init(void) +{ + __GPIOB_CLK_ENABLE(); + __USART1_CLK_ENABLE(); + + GPIO_InitTypeDef GPIO_InitStruct; + + // Init gpio pins for uart + GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; //GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_LOW; + GPIO_InitStruct.Alternate = GPIO_AF1_USART1; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + // Init UART periph + 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; + //huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; + huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXOVERRUNDISABLE_INIT|UART_ADVFEATURE_DMADISABLEONERROR_INIT; + huart1.AdvancedInit.OverrunDisable = UART_ADVFEATURE_OVERRUN_DISABLE; + huart1.AdvancedInit.DMADisableonRxError = UART_ADVFEATURE_DMA_DISABLEONRXERROR; + HAL_UART_Init(&huart1); + + HAL_Delay(100); + uint8_t switch_baud[] = "$PUBX,41,1,0003,0001,115200,0*1E\r\n"; + HAL_UART_Transmit(uart_gethandle(), switch_baud, sizeof(switch_baud)/sizeof(uint8_t), 1000); + + HAL_UART_DeInit(&huart1); + huart1.Init.BaudRate = 115200; + HAL_UART_Init(&huart1); + + +// +// __DMA1_CLK_ENABLE(); +// +// // Init UART DMA +// hdma_usart1_rx.Instance = DMA1_Channel3; +// hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; +// hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; +// hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; +// hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; +// hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; +// hdma_usart1_rx.Init.Mode = DMA_CIRCULAR; +// hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW; +// HAL_DMA_Init(&hdma_usart1_rx); +// +// __HAL_LINKDMA(&huart1,hdmarx,hdma_usart1_rx); +// +// hdma_usart1_tx.Instance = DMA1_Channel2; +// hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; +// hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE; +// hdma_usart1_tx.Init.MemInc = DMA_MINC_DISABLE; +// hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; +// hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; +// hdma_usart1_tx.Init.Mode = DMA_NORMAL; +// hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW; +// HAL_DMA_Init(&hdma_usart1_tx); +// +// __HAL_LINKDMA(&huart1,hdmatx,hdma_usart1_tx); +// +//// HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0, 0); +//// HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); + + HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); + //HAL_NVIC_EnableIRQ(USART1_IRQn); + HAL_NVIC_DisableIRQ(USART1_IRQn); + + uart_initted = 1; +} + +void uart_deinit(void) +{ + if(uart_initted == 1) + { + //HAL_DMA_DeInit(&hdma_usart1_rx); + //HAL_DMA_DeInit(&hdma_usart1_tx); + HAL_UART_DeInit(&huart1); + __HAL_RCC_USART1_CLK_DISABLE(); + + uart_initted = 0; + } +} + +UART_HandleTypeDef* uart_gethandle(void) +{ + return &huart1; +} + +DMA_HandleTypeDef* uart_get_txdma_handle(void) +{ + return &hdma_usart1_tx; +} +DMA_HandleTypeDef* uart_get_rxdma_handle(void) +{ + return &hdma_usart1_rx; +} +