some experiments with a chinese stm8s103
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
stm8s_experiments/User/fncgen.c

294 lines
6.6 KiB

#include "stm8s.h"
#include "fncgen.h"
/** Get 14-bit LSB from a 28-bit value */
#define FREQ_LSB(reg) (u16)(0x3FFF & (reg))
/** Get 14-bit MSB from a 28-bit value */
#define FREQ_MSB(reg) (u16)(0x3FFF & ((reg)>>14))
/** Mask applied to the FG CREG to clear any previous waveform preset */
#define FG_WFM_MASK (u16)(FG_OPBITEN | FG_DIV2 | FG_MODE)
/**
* Send 16 bits
* @param word
*/
static void FG_SPI_Send16(uint16_t word)
{
while(!SPI_GetFlagStatus(SPI_FLAG_TXE));
SPI_SendData((u8)(word >> 8));
while(!SPI_GetFlagStatus(SPI_FLAG_TXE));
SPI_SendData((u8)(word));
}
/**
* @brief Write a single word over SPI to a FG
* @param inst - FG instance
* @param word - word to write (16 bits)
*/
static void FG_WriteWord(FG_Instance *inst, uint16_t word)
{
// NSS down
inst->NSS_GPIO->ODR &= ~inst->NSS_PIN;
// Data
FG_SPI_Send16(word);
// Wait for write to complete
while(SPI_GetFlagStatus(SPI_FLAG_BSY));
// NSS up
inst->NSS_GPIO->ODR |= inst->NSS_PIN;
}
/**
* @brief Manually start a FG data frame
* This function may be used for broadcasting register
* changes to multiple devices (ie. FG_RESET release
* for phase synchronisation)
*
* @param inst - FG instance
*/
void FG_JoinBroadcast(FG_Instance *inst)
{
// NSS down
inst->NSS_GPIO->ODR &= ~inst->NSS_PIN;
}
/**
* @brief Manually end a FG data frame
* This function is used to terminate a broadcast session.
*
* @param inst - FG instance
*/
void FG_LeaveBroadcast(FG_Instance *inst)
{
// Wait for write to complete
while(SPI_GetFlagStatus(SPI_FLAG_BSY));
// NSS up
inst->NSS_GPIO->ODR |= inst->NSS_PIN;
}
/**
* @brief Flush the CREG instance variable to the device
* @param inst - FG instance
*/
static inline void FG_WriteCREG(FG_Instance *inst)
{
FG_WriteWord(inst, inst->CREG);
}
/**
* @brief Set frequency in a bank register
* Change is immediately applied if the bank is active.
*
* @param inst - FG instance
* @param bank - bank number
* @param regval - new frequency register value (28 bits)
*/
void FG_SetFreq(FG_Instance *inst, FG_FreqBank bank, u32 regval)
{
u16 word;
// Ensure B28 is set
if (!(inst->CREG & FG_B28)) {
inst->CREG |= FG_B28;
FG_WriteCREG(inst);
}
word = (bank == FREQ0 ? FG_ADDR_FREQ0 : FG_ADDR_FREQ1);
FG_WriteWord(inst, word | FREQ_LSB(regval)); // 14 bits LSB
FG_WriteWord(inst, word | FREQ_MSB(regval)); // 14 bits MSB
}
/**
* @brief Set frequency MSB in a bank register
* Change is immediately applied if the bank is active.
*
* @param inst - FG instance
* @param bank - frequency bank to change
* @param lsb14 - upper 14 bits of the frequency register
*/
void FG_SetFreqMSB(FG_Instance *inst, FG_FreqBank bank, u16 msb14)
{
u16 word;
// Ensure B28 is cleared
if ((inst->CREG & (FG_B28 | FG_HLB)) != FG_HLB) {
inst->CREG &= ~FG_B28;
inst->CREG |= FG_HLB;
FG_WriteCREG(inst);
}
word = (bank == FREQ0 ? FG_ADDR_FREQ0 : FG_ADDR_FREQ1);
FG_WriteWord(inst, word | (u16)(msb14 & 0x3FFF)); // 14 bits LSB
}
/**
* @brief Set frequency LSB in a bank register
* Change is immediately applied if the bank is active.
*
* @param inst - FG instance
* @param bank - frequency bank to change
* @param lsb14 - lower 14 bits of the frequency register
*/
void FG_SetFreqLSB(FG_Instance *inst, FG_FreqBank bank, u16 lsb14)
{
u16 word;
// Ensure B28 is cleared
if ((inst->CREG & (FG_B28 | FG_HLB)) != 0) {
inst->CREG &= ~FG_B28;
inst->CREG &= ~FG_HLB;
FG_WriteCREG(inst);
}
word = (bank == FREQ0 ? FG_ADDR_FREQ0 : FG_ADDR_FREQ1);
FG_WriteWord(inst, word | (u16)(lsb14 & 0x3FFF)); // 14 bits LSB
}
/**
* @brief Select active frequency bank (for FSK)
* @param inst - FG instance
* @param bank - bank number
*/
void FG_FreqSwitch(FG_Instance *inst, FG_FreqBank bank)
{
if (bank == FREQ0) {
inst->CREG &= ~FG_FSELECT;
} else {
inst->CREG |= FG_FSELECT;
}
FG_WriteCREG(inst);
}
/**
* @brief Set phase in a bank register
* Change is immediately applied if the bank is active.
*
* @param inst - FG instance
* @param bank - bank number
* @param regval - new phase register value (12 bits)
*/
void FG_SetPhase(FG_Instance *inst, FG_PhaseBank bank, u16 regval)
{
u16 word = (bank == PHASE0 ? FG_ADDR_PHASE0 : FG_ADDR_PHASE1);
FG_WriteWord(inst, word | (u16) (regval & 0xFFF)); // 12 bits LSB
}
/**
* @brief Select active phase register (for PSK)
* @param inst - FG instance
* @param bank - bank number
*/
void FG_PhaseSwitch(FG_Instance *inst, FG_PhaseBank bank)
{
if (bank == PHASE0) {
inst->CREG &= ~FG_PSELECT;
} else {
inst->CREG |= FG_PSELECT;
}
FG_WriteCREG(inst);
}
/**
* @brief Select a function generator waveform preset
* @param inst - FG instance
* @param wfm - waveform preset (enum)
*/
void FG_SetWaveform(FG_Instance *inst, FG_Waveform wfm)
{
inst->CREG &= ~FG_WFM_MASK;
inst->CREG |= wfm;
FG_WriteCREG(inst);
}
/**
* @brief Suspend a function generator
* Stops the counter, keeping the output constant
*
* @param inst - FG instance
*/
void FG_Suspend(FG_Instance *inst)
{
inst->CREG |= FG_SLEEP1;
FG_WriteCREG(inst);
}
/**
* @brief Resume a function generator from suspend state *
* @param inst - FG instance
*/
void FG_Resume(FG_Instance *inst)
{
inst->CREG &= ~FG_SLEEP1;
FG_WriteCREG(inst);
}
/**
* @brief Enable or disable a function generator
* When the FG is disabled, the output goes to a midpoint and
* counting registers are reset.
*
* @param inst - FG instance
* @param enable - enable status
*/
void FG_Cmd(FG_Instance *inst, FunctionalState enable)
{
if (enable == ENABLE) {
inst->CREG &= ~FG_RESET;
} else {
inst->CREG |= FG_RESET;
}
FG_WriteCREG(inst);
}
void FG_Reset(FG_Instance *inst)
{
// Stop, enable fullsize freq writes
inst->CREG = FG_B28 | FG_RESET;
FG_WriteCREG(inst);
FG_SetFreq(inst, FREQ0, HZ_REG(500));
FG_SetFreq(inst, FREQ1, 0);
FG_SetPhase(inst, PHASE0, 0);
FG_SetPhase(inst, PHASE1, 0);
}
/**
* @brief Configure a function generator
* Sets up the GPIO pin and resets the target.
* SPI must already be configured!
*
* @param inst - FG instance
* @param NSS_GPIO - port with the slave select pin
* @param NSS_PIN - slave slect pin position
*/
void FG_Init(FG_Instance *inst, GPIO_TypeDef *NSS_GPIO, GPIO_Pin_TypeDef NSS_PIN)
{
GPIO_Init(NSS_GPIO, NSS_PIN, GPIO_MODE_OUT_PP_HIGH_FAST);
inst->NSS_GPIO = NSS_GPIO;
inst->NSS_PIN = NSS_PIN;
FG_Reset(inst);
}
/**
* @brief Configure SPI for talking to FG devices
* Sets up GPIOs and inits the SPI peripheral
*/
void FG_SPI_Init(void)
{
// MOSI, SCK
GPIO_Init(GPIOC, GPIO_PIN_5 | GPIO_PIN_6, GPIO_MODE_OUT_PP_HIGH_FAST);
SPI_Init(SPI_FIRSTBIT_MSB,
SPI_BAUDRATEPRESCALER_2,
SPI_MODE_MASTER,
SPI_CLOCKPOLARITY_HIGH,
SPI_CLOCKPHASE_1EDGE,
SPI_DATADIRECTION_1LINE_TX,
SPI_NSS_SOFT,
0);
SPI_Cmd(ENABLE);
}