Changeset - 851511077b87
[Not reviewed]
default
0 4 0
Ethan Zonca (ethanzonca) - 9 years ago 2017-01-03 15:13:32
e@ethanzonca.com
Fix issue where miso was never initted
4 files changed with 7 insertions and 10 deletions:
0 comments (0 inline, 0 general)
Libraries/Si446x/si446x.c
Show inline comments
 
@@ -32,394 +32,395 @@ void si446x_init(void)
 
	GPIO_InitStruct.Pin = SI446x_TCXO_EN_PIN;
 
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 
	GPIO_InitStruct.Pull = GPIO_NOPULL;
 
	HAL_GPIO_Init(SI446x_TCXO_EN_PORT, &GPIO_InitStruct);
 
	HAL_GPIO_WritePin(SI446x_TCXO_EN_PORT, SI446x_TCXO_EN_PIN, 1);
 
 
	// GPIO: VHF radio shutdown control
 
	GPIO_InitStruct.Pin = SI446x_SHUTDOWN_PIN;
 
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 
	GPIO_InitStruct.Pull = GPIO_NOPULL;
 
	HAL_GPIO_Init(SI446x_SHUTDOWN_PORT, &GPIO_InitStruct);
 
 
	// Perform PoR (takes 20ms) and turn device on
 
	si446x_reset();
 
 
    // Divide SI446x_VCXO_FREQ into its bytes; MSB first
 
    uint16_t x3 = SI446x_VCXO_FREQ / 0x1000000;
 
    uint16_t x2 = (SI446x_VCXO_FREQ - x3 * 0x1000000) / 0x10000;
 
    uint16_t x1 = (SI446x_VCXO_FREQ - x3 * 0x1000000 - x2 * 0x10000) / 0x100;
 
    uint16_t x0 = (SI446x_VCXO_FREQ - x3 * 0x1000000 - x2 * 0x10000 - x1 * 0x100);
 
 
    // Power up radio module                          boot  xtal  _XO_frequency_
 
 
    //TCXO
 
    const char init_command[] = {SI446x_CMD_POWER_UP, 0x01, 0x01, x3, x2, x1, x0};
 
    si446x_sendcmd(7, init_command, SI446x_CHECK_ACK);
 
 
    HAL_Delay(10);
 
 
	// Change to SPI Ready state EMZ added for re-init, might help on startup
 
	uint8_t change_state_commanda[] = {SI446x_CMD_CHANGE_STATE, 0x02}; //  Change to spi ready
 
    si446x_sendcmd(2, change_state_commanda, SI446x_CHECK_ACK);
 
    HAL_Delay(10);
 
 
    // Radio ready: clear all pending interrupts and get the interrupt status back
 
	uint8_t get_int_status_command[] = {SI446x_CMD_GET_INT_STATUS, 0x00, 0x00, 0x00};
 
    si446x_sendcmd(4, get_int_status_command, SI446x_CHECK_ACK);
 
 
    HAL_Delay(10);
 
 
    // GPIO config: Set all GPIOs LOW; Link NIRQ to CTS; Link SDO to MISO; Max drive strength
 
	uint8_t gpio_pin_cfg_command[] = {
 
    		SI446x_CMD_GPIO_PIN_CFG, // Command
 
			SI446x_GPIO_LOW,      // GPIO0 - Power amp control DAC AD5611 Sync Pin
 
			SI446x_GPIO_INPUT,    // GPIO1 - Input for modulation
 
			SI446x_GPIO_LOW,      // GPIO2 - Blue LED
 
			SI446x_GPIO_NOCHANGE, // GPIO3 - Unused
 
			SI446x_GPIO_NOCHANGE, // NIRQ
 
			SI446x_GPIO_NOCHANGE, // 0x11, // SDO
 
			SI446x_GPIO_NOCHANGE, // Gencfg
 
	};
 
    si446x_sendcmd(8, gpio_pin_cfg_command, SI446x_CHECK_ACK);
 
 
    HAL_Delay(10);
 
 
//	uint8_t tune_xo_cmd[] = {
 
//    		SI446x_CMD_SET_PROPERTY,
 
//			SI446x_XO_TUNE_REGISTER_GROUP,
 
//			0x1, // num data
 
//			SI446x_XO_TUNE_REGISTER_PROP,
 
//			SI446x_CRYSTAL_LOAD_TUNING,
 
//    };
 
//    si446x_sendcmd(5, tune_xo_cmd, SI446x_CHECK_ACK);
 
 
    HAL_Delay(10);
 
 
    // Tune to frequency specified
 
	si446x_setchannel(TUNE_FREQUENCY);
 
 
	HAL_Delay(10);
 
 
    // Set to 2FSK mode
 
    uint8_t modemconfig = SI446x_MOD_TYPE_2FSK | SI446x_MOD_TYPE_SOURCE_DIRECTMODE | SI446x_MOD_TYPE_DIRECT_ASYNCH | SI446x_MOD_TYPE_DIRECT_SOURCE_GPIO1; //SI446x_MOD_TYPE_SOURCE_PACKETHANDLER
 
    uint8_t set_modem_mod_type_command[] = {
 
    		SI446x_CMD_SET_PROPERTY,
 
    		SI446x_MOD_TYPE_REGISTER_GROUP,
 
			0x01, // num data
 
			SI446x_MOD_TYPE_REGISTER_PROP,
 
			modemconfig
 
    };
 
    si446x_sendcmd(5, set_modem_mod_type_command, SI446x_CHECK_ACK);
 
 
    HAL_Delay(10);
 
 
	// Set Si446x initial output power, input to power amp (0-0x7F, 0mW - 40mw?)
 
	uint8_t basepower = 0x02;
 
	// FIXME: basepower should be 0x10 for underperforming units and 0x04 for normal units
 
    uint8_t set_power_level_command[] = {SI446x_CMD_SET_PROPERTY, 0x22, 0x01, 0x01, basepower};
 
	si446x_sendcmd(5, set_power_level_command, SI446x_CHECK_ACK);
 
 
 
	HAL_Delay(10);
 
 
    // Set air data rate
 
    si446x_setdatarate();
 
    HAL_Delay(10);
 
 
	// Tune TX
 
	uint8_t change_state_command[] = {SI446x_CMD_CHANGE_STATE, 0x05}; //  Change to TX tune state
 
    si446x_sendcmd(2, change_state_command, SI446x_CHECK_ACK);
 
    HAL_Delay(10);
 
 
	si446x_cw_status = 0;
 
}
 
 
 
// Perform power-on-reset of Si446x. Takes 20ms.
 
void si446x_reset(void)
 
{
 
	si446x_shutdown();
 
	HAL_Delay(10);
 
	si446x_wakeup();
 
	HAL_Delay(10);
 
}
 
 
 
// Set GPIO pin state on Si446x
 
void si446x_gpio(uint8_t gpio, uint8_t state, uint8_t doack)
 
{
 
	// GPIO invalid
 
	if(gpio > 7)
 
		return;
 
 
	// Default to not changing any GPIO
 
	uint8_t gpio_pin_cfg_command[] = {
 
			SI446x_CMD_GPIO_PIN_CFG, // Command
 
			SI446x_GPIO_NOCHANGE, // GPIO0 - Power amp control DAC AD5611 Sync Pin
 
			SI446x_GPIO_NOCHANGE, // GPIO1 - Input for modulation
 
			SI446x_GPIO_NOCHANGE, // GPIO2 - Blue
 
			SI446x_GPIO_NOCHANGE, // GPIO3 - Unused
 
			SI446x_GPIO_NOCHANGE, // NIRQ
 
			SI446x_GPIO_NOCHANGE, // 0x11, // SDO
 
			SI446x_GPIO_NOCHANGE, // Gencfg
 
	};
 
 
	// Set requested GPIO to requested state
 
	gpio_pin_cfg_command[gpio+1] = state;
 
 
	si446x_sendcmd(8, gpio_pin_cfg_command, doack);
 
}
 
 
 
// Set over-air data rate
 
void si446x_setdatarate(void)
 
{
 
    // Set data rate (unsure if this actually affects direct modulation)
 
                         //        set prop   group     numprops  startprop   data
 
	uint8_t set_data_rate_command[] = {SI446x_CMD_SET_PROPERTY,     0x20,     0x03,     0x03,       0x0F, 0x42, 0x40};
 
    si446x_sendcmd(7, set_data_rate_command, SI446x_CHECK_ACK);
 
}
 
 
 
// Block write data to the Si446x SPI interface, up to 128 byte length
 
void si446x_senddata(uint8_t* data, uint8_t len)
 
{
 
	uint8_t dummy[128];
 
	SI446x_SELECT;
 
	HAL_SPI_TransmitReceive(&hspi1, data, dummy, len, SI446x_TIMEOUT);
 
	SI446x_DESELECT;
 
}
 
 
 
// Delay approximately 20us
 
static void delay_cycles(void)
 
{
 
	uint32_t delay_cycles = 180;
 
	while(delay_cycles>0)
 
	{
 
		asm("NOP");
 
		delay_cycles--;
 
	}
 
}
 
 
 
// Send a command to the radio (Blocking)
 
// Avoid calling this during code runtime as it will block for a significant period of time due to delays
 
void si446x_sendcmd(uint8_t tx_len, uint8_t* data, uint8_t doack)
 
{
 
    SI446x_SELECT;
 
 
    delay_cycles();
 
 
    uint8_t dummyrx[25];
 
    if(tx_len >=25)
 
    {
 
    	SI446x_DESELECT;
 
    	return;
 
    }
 
 
    // using transmit receive to transmit data because it actually blocks until the data is sent
 
    // an additional byte is added on to the transmission so we can receive the CTS byte
 
 
    HAL_StatusTypeDef res = HAL_SPI_TransmitReceive(&hspi1, data, dummyrx, tx_len+1, SI446x_TIMEOUT);
 
    volatile HAL_StatusTypeDef res = HAL_SPI_TransmitReceive(&hspi1, data, dummyrx, tx_len+1, SI446x_TIMEOUT);
 
 
    if(res != HAL_OK)
 
    {
 
    	SI446x_DESELECT;
 
    	return;
 
    }
 
 
    SI446x_DESELECT;
 
 
    // If checking for the ACK, perform a SPI read and see if the command was acknowledged
 
    if(doack)
 
    {
 
		delay_cycles();
 
 
		SI446x_SELECT;
 
 
		int reply = 0x00;
 
		uint8_t tx_requestack[2];
 
		tx_requestack[0] = SI446x_CMD_READ_CMD_BUFF;
 
		tx_requestack[1] = 0x00;
 
 
		uint16_t attempts = 0;
 
		volatile uint16_t attempts = 0;
 
 
		// Keep trying receive until it returns 0xFF (successful ACK)
 
		while (reply != 0xFF)
 
		{
 
			// Attempt to receive two bytes from the Si446x which should be an ACK
 
			uint8_t tmprx[2] = {0,0};
 
			res = HAL_SPI_TransmitReceive(&hspi1, tx_requestack, tmprx, 2, SI446x_TIMEOUT);
 
			if(res != HAL_OK)
 
			{
 
				//error_assert_silent(ERR_VHF_SPIBUSY);
 
		    	break; // Break out, deinit, and exit
 
			}
 
			reply = tmprx[1];
 
 
			// Cycle chip select line on and off
 
			if (reply != 0xFF)
 
			{
 
				delay_cycles();
 
				SI446x_DESELECT;
 
				delay_cycles();
 
				SI446x_SELECT;
 
				delay_cycles();
 
				//HAL_GPIO_TogglePin(LED_ACT);
 
			}
 
 
			// Maximum number of attempts exceeded
 
			if(attempts > 1024)
 
			{
 
				//error_assert_silent(ERR_VHF_TIMEOUT);
 
				volatile uint32_t test = 344;
 
				break; // Break out, deinit and exit
 
			}
 
			attempts++;
 
		}
 
    }
 
 
    // Turn off activity LED
 
    //HAL_GPIO_WritePin(LED_ACT, GPIO_PIN_RESET);
 
 
    SI446x_DESELECT;
 
    delay_cycles();
 
}
 
 
 
// Set transmit frequency of Si446x
 
void si446x_setchannel(uint32_t frequency)
 
{
 
 
    // Set the output divider according to recommended ranges given in si446x datasheet
 
    uint32_t outdiv = 4;
 
    uint32_t band = 0;
 
    if (frequency < 705000000UL) { outdiv = 6;  band = 1;};
 
    if (frequency < 525000000UL) { outdiv = 8;  band = 2;};
 
    if (frequency < 353000000UL) { outdiv = 12; band = 3;};
 
    if (frequency < 239000000UL) { outdiv = 16; band = 4;};
 
    if (frequency < 177000000UL) { outdiv = 24; band = 5;};
 
 
    uint32_t f_pfd = 2 * SI446x_VCXO_FREQ / outdiv;
 
 
    uint32_t n = ((uint32_t)(frequency / f_pfd)) - 1;
 
 
    float ratio = (float)frequency / (float)f_pfd;
 
    float rest  = ratio - (float)n;
 
 
    uint32_t m = (uint32_t)(rest * 524288UL);
 
 
    // Set the band parameter
 
    uint32_t sy_sel = 8;
 
    uint8_t set_band_property_command[] = {SI446x_CMD_SET_PROPERTY, 0x20, 0x01, 0x51, (band + sy_sel)};
 
    si446x_sendcmd(5, set_band_property_command, SI446x_CHECK_ACK);
 
 
    // Set the pll parameters
 
    uint32_t m2 = m / 0x10000;
 
    uint32_t m1 = (m - m2 * 0x10000) / 0x100;
 
    uint32_t m0 = (m - m2 * 0x10000 - m1 * 0x100);
 
 
    // Assemble parameter string
 
    uint8_t set_frequency_property_command[] = {SI446x_CMD_SET_PROPERTY, 0x40, 0x04, 0x00, n, m2, m1, m0};
 
    si446x_sendcmd(8, set_frequency_property_command, SI446x_CHECK_ACK);
 
 
    // Set frequency deviation
 
    // ...empirically 0xF9 looks like about 5khz. Sketchy.
 
 
    //                           set prop   group     numprops  startprop   data                     // Was 0x0F 00 for ~40kHz dev, switched to 56khzish? dev
 
 
    //2DF5 is correct for 56khz
 
    uint8_t set_frequency_separation[] = {SI446x_CMD_SET_PROPERTY, 0x20,     0x03,      0x0a,     0x00, 0x03, 0x00};
 
    si446x_sendcmd(7, set_frequency_separation, SI446x_CHECK_ACK);
 
 
}
 
 
 
// Turn CW transmit on
 
void si446x_cw_on(void)
 
{
 
    // Change to TX state
 
	uint8_t change_state_command[] = {SI446x_CMD_CHANGE_STATE, 0x07};
 
    si446x_sendcmd(2, change_state_command, SI446x_CHECK_ACK);
 
    si446x_cw_status = 1;
 
}
 
 
 
// Turn CW transmit off
 
void si446x_cw_off(void)
 
{
 
    // Change to ready state
 
	uint8_t change_state_command[] = {SI446x_CMD_CHANGE_STATE, 0x03};
 
    si446x_sendcmd(2, change_state_command, SI446x_CHECK_ACK);
 
    si446x_cw_status = 0;
 
}
 
 
 
// Returns 1 if CW is on or 0 if CW is off
 
inline uint8_t si446x_tx_status(void)
 
{
 
	return si446x_cw_status;
 
}
 
 
 
// Initialize SPI port for generation of direct modulation for Si446x
 
static void __init_spi1(void)
 
{
 
 
	GPIO_InitTypeDef GPIO_InitStruct;
 
 
	// GPIO: VHF chip select
 
	GPIO_InitStruct.Pin = SI446x_CS_PIN;
 
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 
	GPIO_InitStruct.Pull = GPIO_NOPULL;
 
	GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
 
	HAL_GPIO_Init(SI446x_CS_PORT, &GPIO_InitStruct);
 
	SI446x_DESELECT;
 
 
	// SPI pins
 
	__SPI1_CLK_ENABLE();
 
	GPIO_InitStruct.Pin = SI446x_SCK_PIN|SI446x_MOSI_PIN|SI446x_MOSI_PIN;
 
	GPIO_InitStruct.Pin = SI446x_SCK_PIN|SI446x_MOSI_PIN|SI446x_MISO_PIN;
 
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 
	GPIO_InitStruct.Pull = GPIO_NOPULL;
 
	GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
 
	GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
 
	HAL_GPIO_Init(SI446x_SCK_PORT, &GPIO_InitStruct);
 
 
	// SPI peripheral
 
	hspi1.Instance = SPI1;
 
	hspi1.Init.Mode = SPI_MODE_MASTER;
 
 
	hspi1.Init.Direction = SPI_DIRECTION_2LINES;
 
 
	hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
 
	hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // Double-check, this is usually high, but might be low for this chip
 
	hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // was 1edge before (rising edge of clock)
 
	hspi1.Init.NSS = SPI_NSS_SOFT;
 
	hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
 
	hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
 
	hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
 
	hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
 
	hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
 
	hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLED;
 
	HAL_SPI_Init(&hspi1);
 
}
 
 
 
// Place the Si446x into shutdown
 
void si446x_shutdown(void)
 
{
 
    HAL_GPIO_WritePin(SI446x_SHUTDOWN, GPIO_PIN_SET);
 
}
 
 
 
// Wake up the Si446x from shutdown
 
void si446x_wakeup(void)
 
{
 
    HAL_GPIO_WritePin(SI446x_SHUTDOWN, GPIO_PIN_RESET);
 
}
 
 
 
// Accessor for SPI1  handle
 
SPI_HandleTypeDef* spi1_get(void)
 
{
 
	return &hspi1;
 
}
Libraries/Si446x/si446x.h
Show inline comments
 
#ifndef SI446X_H
 
#define SI446X_H
 
 
#include "stm32f0xx_hal.h"
 
 
 
// Hardware Options ///////////////////
 
 
// Timeout for blocking writes
 
#define SI446x_TIMEOUT 10
 
#define SI446x_TIMEOUT 50
 
 
// Crystal/oscillator frequency
 
#define SI446x_VCXO_FREQ  26000000UL
 
#define SI446x_SPI SPI1
 
 
// GPIO assignments
 
#define SI446x_CS_PORT GPIOA
 
#define SI446x_CS_PIN GPIO_PIN_15
 
 
#define SI446x_GPIO_PORT GPIOA
 
#define SI446x_GPIO_PIN GPIO_PIN_10
 
 
#define SI446x_SHUTDOWN_PORT GPIOA
 
#define SI446x_SHUTDOWN_PIN GPIO_PIN_9
 
 
#define SI446x_MOSI_PORT GPIOB
 
#define SI446x_MOSI_PIN GPIO_PIN_5
 
 
#define SI446x_MISO_PORT GPIOB
 
#define SI446x_MISO_PIN GPIO_PIN_4
 
 
#define SI446x_SCK_PORT GPIOB
 
#define SI446x_SCK_PIN GPIO_PIN_3
 
 
 
#define SI446x_TCXO_EN_PORT GPIOA
 
#define SI446x_TCXO_EN_PIN GPIO_PIN_8
 
 
 
///////////////////////////////////////
 
 
 
// Registers /////////////////////////
 
#define SI446x_CMD_POWER_UP 0x02
 
#define SI446x_CMD_NOP 0x00
 
#define SI446x_CMD_PART_INFO 0x01
 
#define SI446x_CMD_FUNC_INFO 0x10
 
#define SI446x_CMD_SET_PROPERTY 0x11
 
#define SI446x_CMD_GET_PROPERTY 0x12
 
#define SI446x_CMD_GPIO_PIN_CFG 0x13
 
#define SI446x_CMD_GET_ADC_READING 0x14
 
#define SI446x_CMD_FIFO_INFO 0x15
 
#define SI446x_CMD_PACKET_INFO 0x16
 
#define SI446x_CMD_IRCAL 0x17
 
#define SI446x_CMD_PROTOCOL_CFG 0x18
 
#define SI446x_CMD_GET_INT_STATUS 0x20
 
#define SI446x_CMD_GET_PH_STATUS 0x21
 
#define SI446x_CMD_GET_MODEM_STATUS 0x22
 
#define SI446x_CMD_GET_CHIP_STATUS 0x23
 
#define SI446x_CMD_START_TX 0x31
 
#define SI446x_CMD_START_RX 0x32
 
#define SI446x_CMD_REQUEST_DEVICE_STATE 0x33
 
#define SI446x_CMD_CHANGE_STATE 0x34
 
#define SI446x_CMD_READ_CMD_BUFF 0x44
 
#define SI446x_CMD_FRR_A_READ 0x50
 
#define SI446x_CMD_FRR_B_READ 0x51
 
#define SI446x_CMD_FRR_C_READ 0x53
 
#define SI446x_CMD_FRR_D_READ 0x57
 
#define SI446x_CMD_WRITE_TX_FIFO 0x66
 
#define SI446x_CMD_READ_RX_FIFO 0x77
 
#define SI446x_CMD_RX_HOP 0x36
 
 
// GPIO pin configuration options
 
#define SI446x_GPIO_NOCHANGE 0
 
#define SI446x_GPIO_LOW 2
 
#define SI446x_GPIO_HIGH 3
 
#define SI446x_GPIO_INPUT 4
 
#define SI446x_GPIO_TXFIFO_LOW 35
 
#define SI446x_GPIO_TXENABLED 32
 
 
// GPIO pin definitions
 
#define SI446x_GPIO0 0
 
#define SI446x_GPIO1 1
 
#define SI446x_GPIO2 2
 
#define SI446x_GPIO3 3
 
 
// Property MOD_TYPE parameters
 
#define SI446x_MOD_TYPE_REGISTER_GROUP 0x20
 
#define SI446x_MOD_TYPE_REGISTER_PROP 0x00
 
#define SI446x_MOD_TYPE_CW    0
 
#define SI446x_MOD_TYPE_OOK   1
 
#define SI446x_MOD_TYPE_2FSK  2
 
#define SI446x_MOD_TYPE_2GFSK 3
 
#define SI446x_MOD_TYPE_4FSK  4
 
#define SI446x_MOD_TYPE_4GFSK 5
 
 
#define SI446x_MOD_TYPE_SOURCE_PACKETHANDLER (0<<3)
 
#define SI446x_MOD_TYPE_SOURCE_DIRECTMODE    (1<<3)
 
#define SI446x_MOD_TYPE_SOURCE_PSEUDORANDOM  (2<<3)
 
 
#define SI446x_MOD_TYPE_DIRECT_SYNCH (0<<7)
 
#define SI446x_MOD_TYPE_DIRECT_ASYNCH (1<<7)
 
 
#define SI446x_MOD_TYPE_DIRECT_SOURCE_GPIO0 (0<<5)
 
#define SI446x_MOD_TYPE_DIRECT_SOURCE_GPIO1 (1<<5)
 
#define SI446x_MOD_TYPE_DIRECT_SOURCE_GPIO2 (2<<5)
 
#define SI446x_MOD_TYPE_DIRECT_SOURCE_GPIO3 (3<<5)
 
 
// XO Tune
 
#define SI446x_XO_TUNE_REGISTER_GROUP 0x00
 
#define SI446x_XO_TUNE_REGISTER_PROP 0x00
 
#define SI446x_XO_TUNE_MAX 0x7F
 
 
// Modem bit mapping
 
#define SI446x_MODEM_MAP_GROUP 0x20
 
#define SI446x_MODEM_MAP_PROP 0x01
 
 
// Preamble
 
#define SI446x_PREAMBLE_TX_LENGTH_GROUP 0x10
 
#define SI446x_PREAMBLE_TX_LENGTH_PROP 0x00
 
 
// Sync
 
#define SI446x_SYNC_LENGTH_GROUP 0x11
 
#define SI446x_SYNC_LENGTH_PROP 0x00
 
 
 
// Power amp control DAC options
 
#define AD56XX_NORMAL_OPERATION 0b00000000
 
#define AD56XX_1K_TO_GROUND     0b01000000
 
#define AD56XX_100K_TO_GROUND   0b10000000
 
#define AD56XX_TRI_STATE        0b11000000
 
 
 
 
// Internal definitions
 
#define SI446x_CS SI446x_CS_PORT, SI446x_CS_PIN
 
#define SI446x_MOSI SI446x_MOSI_PORT, SI446x_MOSI_PIN
 
#define SI446x_MISO SI446x_MISO_PORT, SI446x_MISO_PIN
 
#define SI446x_SCK SI446x_SCK_PORT, SI446x_SCK_PIN
 
#define SI446x_GPIO SI446x_GPIO_PORT, SI446x_GPIO_PIN
 
#define SI446x_SHUTDOWN SI446x_SHUTDOWN_PORT , SI446x_SHUTDOWN_PIN
 
 
 
// Communication options
 
#define SI446x_IGNORE_ACK 0
 
#define SI446x_CHECK_ACK 1
 
 
 
// Helper macros
 
#define SI446x_SELECT HAL_GPIO_WritePin(SI446x_CS, GPIO_PIN_RESET)
 
#define SI446x_DESELECT HAL_GPIO_WritePin(SI446x_CS, GPIO_PIN_SET)
 
 
void si446x_init(void);
 
 
void si446x_reset(void);
 
 
void si446x_gpio(uint8_t gpio, uint8_t state, uint8_t doack);
 
 
void si446x_setdatarate(void);
 
 
void si446x_senddata(uint8_t* data, uint8_t len);
 
void si446x_sendcmd(uint8_t tx_len, uint8_t* data, uint8_t doack);
 
 
 
void si446x_setchannel(uint32_t frequency);
 
 
void si446x_cw_on(void);
 
void si446x_cw_off(void);
 
uint8_t si446x_tx_status(void);
 
 
SPI_HandleTypeDef* spi1_get(void);
 
 
void si446x_shutdown(void);
 
void si446x_wakeup(void);
 
 
#endif
Libraries/aprs/afsk.c
Show inline comments
 
@@ -86,221 +86,217 @@ volatile TIM_HandleTypeDef htim1;
 
////////////////////////////////////////////////
 
void afsk_init(void) 
 
{
 
    GPIO_InitTypeDef GPIO_InitStruct;
 
    GPIO_InitStruct.Pin = GPIO_PIN_10;
 
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 
    GPIO_InitStruct.Pull = GPIO_NOPULL;
 
    //GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM1;
 
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 

	
 
//    __HAL_RCC_TIM1_CLK_ENABLE();
 

	
 
    __TIM1_CLK_ENABLE();
 

	
 
	TIM_MasterConfigTypeDef sMasterConfig;
 
	TIM_OC_InitTypeDef sConfigOC;
 
	TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
 

	
 
	htim1.Instance = TIM1;
 
	htim1.Init.Prescaler = 1;
 
	htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
 
	htim1.Init.Period = 255;
 
	htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
 
	htim1.Init.RepetitionCounter = 0;
 
	HAL_TIM_OC_Init(&htim1);
 

	
 
	sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
 
	sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
 
	HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
 

	
 
	sConfigOC.OCMode = TIM_OCMODE_PWM1;
 
	sConfigOC.Pulse = 300;
 
	sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
 
	sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
 
	sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
 
	sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
 
	sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
 
	HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3);
 

	
 
	sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
 
	sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
 
	sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
 
	sBreakDeadTimeConfig.DeadTime = 0;
 
	sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
 
	sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
 
	sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
 
	HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
 

	
 
//
 
//
 
//    // Init gpio of pin
 
//    gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO10); //pa10 radio gp1
 
//    gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_HIGH,  GPIO10);
 
//    gpio_set_af(GPIOA, GPIO_AF2, GPIO10);
 
//
 
//    // Reset and configure timer
 
//    timer_reset(TIM1);
 
//    //TIM_CR1_CKD_CK_INT_MUL_4
 
//    timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, //TIM_CR1_CMS_CENTER_1,
 
//                       TIM_CR1_DIR_UP);
 
//    timer_set_prescaler(TIM1, 1); // 155 is 1200hz, 84 is 2200hz
 
//
 
//
 
//    timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);
 
//    timer_enable_oc_output(TIM1, TIM_OC3);
 
//    timer_enable_break_main_output(TIM1);
 
//    timer_set_oc_value(TIM1, TIM_OC3, 300);
 
//    timer_set_period(TIM1, 255); // should this be 256? FIXME
 
//    timer_enable_counter(TIM1);
 
//
 
//    // Enable interrupt for timer capture/compare
 
//    timer_enable_irq(TIM1, TIM_DIER_CC3IE);
 

	
 
    while(afsk_busy());
 
	//HAL_TIM_OC_Start_IT(&htim1, TIM_CHANNEL_3);
 

	
 
//    HAL_NVIC_SetPriority(TIM1_CC_IRQn, 0, 0);
 
    HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0, 0);
 
//	HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);
 
	HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
 

	
 
}
 

	
 

	
 
void afsk_output_sample(uint8_t s)
 
{
 
    //timer_set_oc_value(TIM1, TIM_OC3, s);
 
    htim1.Instance->CCR3 = s;
 
}
 

	
 
uint8_t afsk_request_cwoff(void)
 
{
 
    if(request_cwoff)
 
    {
 
        request_cwoff = 0;
 
        return 1;
 
    }
 
    else
 
    {
 
        return 0;
 
    }
 
}
 

	
 
volatile uint32_t freqctr = 0;
 

	
 
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
 
{
 
	if (go) {
 
			if (packet_pos == afsk_packet_size)
 
			{
 
					request_cwoff = 1;
 
					//gpio_toggle(GPIOB, GPIO0);
 
					//gpio_toggle(GPIOB, GPIO7);
 
					go = 0;         // End of transmission
 
					afsk_timer_stop();  // Disable modem
 
					return; // done
 
			}
 

	
 
			// If sent SAMPLES_PER_BAUD already, go to the next bit
 
			if (current_sample_in_baud == 0)  // Load up next bit
 
			{
 
					if ((packet_pos & 7) == 0) // Load up next byte
 
					{
 
							current_byte = afsk_packet[packet_pos >> 3];
 
					}
 
					else
 
					{
 
							current_byte = current_byte / 2;  // ">>1" forces int conversion
 
					}
 
					if ((current_byte & 1) == 0)
 
					{
 
							// Toggle tone (1200 <> 2200)
 
							phasedelta ^= (PHASE_DELTA_1200 ^ PHASE_DELTA_2200);
 
					}
 
			}
 

	
 
			phase += phasedelta;
 
			uint8_t s = afsk_read_sample((phase >> 7) & (TABLE_SIZE - 1));
 

	
 
			afsk_output_sample(s); //real afsk
 

	
 
			if(++current_sample_in_baud == SAMPLES_PER_BAUD)
 
			{
 
					current_sample_in_baud = 0;
 
					packet_pos++;
 
			}
 

	
 
	}
 
}
 

	
 

	
 
void afsk_timer_start()
 
{
 
    // Clear the overflow flag, so that the interrupt doesn't go off
 
    // immediately and overrun the next one (p.163).
 
    // Enable interrupt when TCNT2 reaches TOP (0xFF) (p.151, 163)
 
    //nvic_enable_irq(NVIC_TIM1_CC_IRQ);
 
//	HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);
 
	HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
 
	__HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
 
	HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_3);
 

	
 
    //timer_enable_counter(TIM1);
 
}
 

	
 
void afsk_timer_stop()
 
{
 
	// Resting duty cycle
 
	// Output 0v (could be 255/2, which is 0v after coupling... doesn't really matter)
 
	//OCR2A = 0x80;
 

	
 
	// Disable playback interrupt
 
	//TIMSK2 &= ~_BV(TOIE2);
 
    //nvic_disable_irq(NVIC_TIM1_CC_IRQ);
 
//	HAL_NVIC_DisableIRQ(TIM1_CC_IRQn);
 
//	HAL_NVIC_DisableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);
 
	HAL_TIM_PWM_Stop_IT(&htim1, TIM_CHANNEL_3);
 
    //timer_disable_counter(TIM1);
 
}
 

	
 

	
 
// External
 

	
 
void afsk_start(void)
 
{
 
	phasedelta = PHASE_DELTA_1200;
 
	phase = 0;
 
	packet_pos = 0;
 
	current_sample_in_baud = 0;
 
	go = 1;
 

	
 
    // Wake up and configure radio
 
    //si446x_prepare();
 
    HAL_Delay(100);
 

	
 
	// Key the radio
 
	si446x_cw_on();
 

	
 
	// Start transmission
 
	afsk_timer_start();
 
}
 

	
 
uint8_t afsk_busy(void)
 
{
 
	return go;
 
}
 

	
 
void afsk_send(const uint8_t *buffer, uint16_t len)
 
{
 
	afsk_packet_size = len;
 
	afsk_packet = buffer;
 
}
 

	
 
TIM_HandleTypeDef* afsk_timer_gethandle(void)
 
{
 
	return &htim1;
 
}
 

	
 

	
 
// vim:softtabstop=4 shiftwidth=4 expandtab 
Source/main.c
Show inline comments
 
//
 
// mBuoy Depth Select Firmware
 
// Copyright 2015 SeaLandAire Technologies
 
//
 
 
#include "config.h"
 
#include "error.h"
 
#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)
 
{
 
  hal_init();
 
  sysclock_init();
 
  gpio_init();
 
 
 
  afsk_init();
 
  si446x_init();
 
  gps_poweron();
 
 
  // Software timers
 
  uint32_t last_led = HAL_GetTick();
 
 
  while (1)
 
  {
 
	  // Blink LEDs
 
	  if(HAL_GetTick() - last_led > 1500)
 
	  if(HAL_GetTick() - last_led > 50)
 
	  {
 
		  gps_update_data();
 
		  aprs_send();
 
		  while(afsk_busy());
 
 
		  last_led = HAL_GetTick();
 
	  }
 
 
	  if(afsk_request_cwoff())
 
		  si446x_cw_off();
 
 
	  // High-frequency function calls
 
//	  gpio_process_shutdown();
 
//	  watchdog_feed();
 
  }
 
}
 
0 comments (0 inline, 0 general)