Firstly you have to config SPI to run slow enough to assure the 125kbytes/sec tx rate is not exceeded (a lot of BS is written online about this, but it is real)
m_spi.Init.Direction = SPI_DIRECTION_2LINES;
m_spi.Init.DataSize = SPI_DATASIZE_8BIT;
m_spi.Init.CLKPolarity = SPI_POLARITY_LOW;
m_spi.Init.CLKPhase = SPI_PHASE_1EDGE;
m_spi.Init.NSS = SPI_NSS_SOFT;
m_spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; // 64: 650kHz (max 1MHz for 125kbyte/sec max data rate)
m_spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
m_spi.Init.CRCPolynomial = 7;
m_spi.Init.Mode = SPI_MODE_MASTER;
m_spi.Instance = NEO_M9N_SPI;
HAL_SPI_Init(&m_spi);
This is the init code
void neo_m9n_init()
{
// Initialise internal (SPI) GPS
{
#ifndef TEST_DATA
uint8_t tmp;
for (uint16_t i=0; i < sizeof(neo_m9n_init_data); i++)
{
kde_neo_m9n_spi3_write_read_byte(neo_m9n_init_data[i], &tmp);
osDelay(2); // this delay removes any need for SPI speed limit when feeding the GPS
}
#endif
debug_thread_printf("GPS init sent to SPI");
}
/*
* NEO-M9N GPS byte write+read over SPI.
* For normal data read, transmit 0xFF. If you get 0xFF back, that indicates an under-run so discard it.
* The read speed is limited to 125kbytes/sec and this is supposed to avoid under-runs *within* packets, which is
* necessary otherwise binary packets could not be received! This issue has been sidestepped by not implementing
* any binary packets.
* We achieve the 125kbyte/sec limit (equivalent to a 1MHz SPI clock) by running SPI3 at 650kHz clock which is
* the nearest value below 1MHz. However since we aren't processing binary packets (GET_UBX_NAV_SAT not defined)
* we could run SPI a lot faster, except that will overspeed the SPI *to* the GPS.
* It is a truly shit interface, but much faster than a UART even at 115kbaud, and avoids using up any of our
* four serial ports. In any case, none of the four serial ports come out on the two expansion connectors.
* In normal operation, this function will return solid FFs during the inter-packet gaps (every 200ms) and
* should return few if any FFs during the packets.
*
*/
static void kde_neo_m9n_spi3_write_read_byte(uint8_t out_value, uint8_t * ret_value)
{
// These are static so DMA can be used
static uint8_t outv = 0;
static uint8_t inv = 0;
outv = out_value;
kde_neo_m9n_cs(0);
hang_around_us(1);
SPI3_DMA_TransmitReceive(&outv, &inv, 1, false, false, RTOS_YIELD);
hang_around_us(1); // 1 microsecond
kde_neo_m9n_cs(1);
*ret_value = inv;
}
I am not posting the DMA code; you don't really need it since the speed here is so low.
The code shows SPI3 is mutexed; you may not need to do that if not sharing SPI3.
Here is the init data and you tweak that to select which packets you want
/*
*
* Transmit config data block to the GPS.
* This disables various default NMEA messages (sentences) and selects three proprietary U-BLOX messages
* which were chosen to return not just location but also HDOP and VDOP, and whether SBAS is being used.
* The GPS is set to run, and emit the basic position and HDOP/VDOP, at 5Hz which is important for high quality
* positioning purposes.
* The satellite status messages come out at 1Hz because they are not needed as often, and due to their size
* would overrun the 38k serial baud rate.
* This configuration results in about 1.4kbytes/sec coming from the GPS, which is manageable at 38k.
* Working out this config was a bastard. Each config message below ends with a checksum and U-BLOX have
* special software for composing these and calculating the checksums. I managed to extract these messages
* from their tech support.
*
* Port is 1 2 3 4 for serial ports 1 2 3 4. 3 is not used because it is 2-wire RS485.
* Port of -1 means internal (SPI) GPS.
*
* Unless SPI GPS is used, the size of the init block must be no bigger than opqspace(g_gps_port)! This
* was done to avoid a blocking call and yet another timeout, etc.
* Currently the opqspace is 1k.
*
*/
static const uint8_t neo_m9n_init_data[] =
{
// 0xB5,0x62,0x06,0x01,0x03,0x00,0xF0,0x08,0x01,0x03,0x20, // enable ZDA
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x23, // disable GGA
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2A, // disable GLL
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x31, // disable GSA
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x38, // disable GSV
// 0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x3F, // disable RMC
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x46, // disable VTG
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x5B, // disable ZDA
#ifndef RMC_ONLY
0xB5,0x62,0x06,0x01,0x03,0x00,0xF1,0x00,0x01,0xFC,0x13, // enable PUBX,00
#endif
0xB5,0x62,0x06,0x08,0x06,0x00,0xC8,0x00,0x01,0x00,0x01,0x00,0xDE,0x6A, // GPS rate 5 Hz
// UBX-NAV-SAT (0x01 0x35) at 5Hz - satellite data, binary
// B5 62 06 01 03 00 01 35 01 41 AD
#ifndef RMC_ONLY
// above at 1Hz - preferred for less data
#ifdef GET_UBX_NAV_SAT
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x35, 0x05, 0x45, 0xB1, // enable UBX-NAV-SAT at 1/5 of rate = 1Hz
#endif
// PUBX,03 (Satellite data, ASCII) and at 5Hz
// B5 62 06 01 03 00 F1 03 01 FF 19
// above at 1Hz - preferred for less data
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF1, 0x03, 0x05, 0x03, 0x1D // enable PUBX,03 at 1/5 of rate = 1Hz
#endif
// This saves the config in flash, UBX-CFG-CFG
// NOT doing this on new devices because there is no evident factory reset!
// 0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1D, 0xAB
};
Hope this helps.
The SPI interface on this module is a bodge. They probably stuck it on the front of their UART, sort of.