/* * spreadspace avr utils * * * Copyright (C) 2013 Christian Pointner * Othmar Gsenger * * This file is part of spreadspace avr utils. * * spreadspace avr utils is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * spreadspace avr utils is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with spreadspace avr utils. If not, see . */ #include "LUFA/Drivers/Peripheral/TWI.h" #include #include "rda1846.h" #include "rda1846_defines.h" static uint8_t rda1846_write_register_raw(const uint8_t addr, const uint16_t data) { if(TWI_StartTransmission(RDA1846_CHIP_ADDR | TWI_ADDRESS_WRITE,10) != TWI_ERROR_NoError) return 1; if(!TWI_SendByte(addr | RDA1846_ADDR_W)) goto i2c_error; if(!TWI_SendByte((uint8_t)(data>>8))) goto i2c_error; if(!TWI_SendByte((uint8_t)data)) goto i2c_error; TWI_StopTransmission(); return 0; i2c_error: TWI_StopTransmission(); printf("I2C error (write_register_raw)\r\n"); return 1; } static uint8_t rda1846_read_register_raw(const uint8_t addr, uint16_t* data) { if(TWI_StartTransmission(RDA1846_CHIP_ADDR | TWI_ADDRESS_WRITE,10) != TWI_ERROR_NoError) return 1; if(!TWI_SendByte(addr | RDA1846_ADDR_R)) goto i2c_error; if(TWI_StartTransmission(RDA1846_CHIP_ADDR | TWI_ADDRESS_READ,10) != TWI_ERROR_NoError) goto i2c_error; uint8_t tmp; if(!TWI_ReceiveByte(&tmp, 0)) goto i2c_error; *data = tmp << 8; if(!TWI_ReceiveByte(&tmp, 1)) goto i2c_error; *data |= tmp; TWI_StopTransmission(); return 0; i2c_error: TWI_StopTransmission(); printf("I2C error (write_register_raw)\r\n"); return 1; } static uint8_t rda1846_write_register(const uint8_t addr, const uint16_t data) { if(addr < RDA1846_ADDR_LIMIT) return rda1846_write_register_raw(addr, data); if(addr > RDA1846_ADDR_LIMIT) { uint8_t ret = rda1846_write_register_raw(RDA1846_ADDR_LIMIT, 1); if(ret) return ret; ret = rda1846_write_register_raw(addr, data); if(ret) return ret; return rda1846_write_register_raw(RDA1846_ADDR_LIMIT, 0); } return 1; } static uint8_t rda1846_read_register(const uint8_t addr, uint16_t* data) { if(addr < RDA1846_ADDR_LIMIT) return rda1846_read_register_raw(addr, data); if(addr > RDA1846_ADDR_LIMIT) { uint8_t ret = rda1846_write_register_raw(RDA1846_ADDR_LIMIT, 1); if(ret) return ret; ret = rda1846_read_register_raw(addr - RDA1846_ADDR_LIMIT + 1, data); if(ret) return ret; return rda1846_write_register_raw(RDA1846_ADDR_LIMIT, 0); } return 1; } void rda1846_init(void) { TWI_Init(TWI_BIT_PRESCALE_1, TWI_BITLENGTH_FROM_FREQ(1, 200000)); // switch to 2m Band (134 ~ 174 MHz) rda1846_write_register(RDA1846_REG_RF_BAND, RDA1846_RF_BAND_2M); // rda1846_write_register(RDA1846_REG_RF_BAND, RDA1846_RF_BAND_70CM); // set crystal frequency (12.288 MHz) rda1846_write_register(RDA1846_REG_XTAL, RDA1846_XTAL_FREQ); rda1846_write_register(RDA1846_REG_ADCLK, RDA1846_ADCLK_FREQ); rda1846_write_register(RDA1846_REG_CLK_MODE, RDA1846_CLK_MODE); rda1846_write_register(RDA1846_REG_CTL, RDA1846_CTL_CH_12K5 | RDA1846_CTL_RX_M_TX_M | RDA1846_CTL_RX); rda1846_write_register(RDA1846_REG_INT, RDA1846_INT_DTMF_IDLE); // use this if VOX, SQ, TXON_RF, RXON_RF are meant as outputs rda1846_write_register(RDA1846_REG_GPIO, RDA1846_GPIO_7_VOX | RDA1846_GPIO_6_SQ | RDA1846_GPIO_5_TXON_RF | RDA1846_GPIO_4_RXON_RF | RDA1846_GPIO_2_INT); // use this if VOX, SQ, TXON_RF, RXON_RF are meant as inputs // rda1846_write_register(RDA1846_REG_GPIO, RDA1846_GPIO_2_INT); // rda1846_write_register(RDA1846_REG_TX_VOICE, RDA1846_TX_VOICE_NONE); rda1846_write_register(RDA1846_REG_TX_VOICE, RDA1846_TX_VOICE_MIC); // rda1846_write_register(RDA1846_REG_TX_VOICE, RDA1846_TX_VOICE_TONE2); // rda1846_write_register(RDA1846_REG_DTMF_CTL, RDA1846_DTMF_DUAL | RDA1846_DTMF_EN); } void rda1846_powerdown(void) { uint16_t data; if(rda1846_read_register(RDA1846_REG_CTL, &data)) return; data &= ~(RDA1846_CTL_PDN); rda1846_write_register(RDA1846_REG_CTL, data); } void rda1846_wakeup(void) { uint16_t data; if(rda1846_read_register(RDA1846_REG_CTL, &data)) return; data |= RDA1846_CTL_PDN; rda1846_write_register(RDA1846_REG_CTL, data); } void rda1846_receive(void) { uint16_t data; if(rda1846_read_register(RDA1846_REG_CTL, &data)) return; data |= RDA1846_CTL_RX; data &= ~(RDA1846_CTL_TX); rda1846_write_register(RDA1846_REG_CTL, data); } void rda1846_transmit(void) { uint16_t data; if(rda1846_read_register(RDA1846_REG_CTL, &data)) return; data &= ~(RDA1846_CTL_RX); data |= RDA1846_CTL_TX; rda1846_write_register(RDA1846_REG_CTL, data); } void rda1846_soft_reset(void) { rda1846_write_register(RDA1846_REG_CTL, RDA1846_CTL_SOFT_RST); } int16_t rda1846_get_rssi(void) { uint16_t data; if(rda1846_read_register(RDA1846_REG_RSSI, &data)) return -1; return (int16_t)data; } int16_t rda1846_get_vssi(void) { uint16_t data; if(rda1846_read_register(RDA1846_REG_VSSI, &data)) return -1; return (int16_t)data; } uint16_t rda1846_get_flags(void) { uint16_t data; if(rda1846_read_register(RDA1846_REG_FLAG, &data)) return 0xFFFF; return data & 0x1687; } uint8_t rda1846_get_dtmf(uint8_t* idx1, uint8_t* idx2, uint8_t* code) { uint16_t data; if(rda1846_read_register(RDA1846_REG_DTMF_OUT, &data)) return 1; if(idx1) *idx1 = (uint8_t)((data & 0x0380)>>7); if(idx2) *idx2 = (uint8_t)((data & 0x0070)>>4); if(code) *code = (uint8_t)(data & 0x000F); return 0; } int32_t rda1846_get_freq_kHz(void) { int32_t freq; uint16_t data; uint8_t ret = rda1846_read_register(RDA1846_REG_FREQH, &data); if(ret) return -1; freq = (((uint32_t)(data & 0x3FFF))<<16); ret = rda1846_read_register(RDA1846_REG_FREQL, &data); if(ret) return -1; freq += data; return (freq>>3); } #define RDA1846_BAND_LOW 134000 // kHz #define RDA1846_BAND_HIGH 174000 // kHZ uint8_t rda1846_set_freq_kHz(int32_t freq) { /* if(freq < RDA1846_BAND_LOW || freq > RDA1846_BAND_HIGH) */ /* return 1; */ freq = freq<<3; uint8_t ret = rda1846_write_register(RDA1846_REG_FREQH, ((freq>>16) & 0x0000FFFF)); if(ret) return 1; return rda1846_write_register(RDA1846_REG_FREQL, (freq & 0x0000FFFF)); } char* rda1846_regaddr_to_string(uint8_t addr) { switch(addr) { case RDA1846_REG_CTL: return "CTL"; case RDA1846_REG_GPIO: return "GPIO"; case RDA1846_REG_INT: return "INT"; case RDA1846_REG_FLAG: return "FLAG"; case RDA1846_REG_RSSI: return "RSSI"; case RDA1846_REG_VSSI: return "VSSI"; case RDA1846_REG_CLK_MODE: return "CLK_MODE"; case RDA1846_REG_XTAL: return "XTAL"; case RDA1846_REG_ADCLK: return "ADCLK"; case RDA1846_REG_RF_BAND: return "RF_BAND"; case RDA1846_REG_FREQH: return "FREQH"; case RDA1846_REG_FREQL: return "FREQL"; case RDA1846_REG_PA_BIAS: return "PA_BIAS"; case RDA1846_REG_TX_VOICE: return "TX_VOICE"; case RDA1846_REG_VOX_OPEN: return "VOX_OPEN"; case RDA1846_REG_VOX_SHUT: return "VOX_SHUT"; case RDA1846_REG_SUBAUDIO: return "SUBAUDIO"; case RDA1846_REG_SQ_OPEN: return "SQ_OPEN"; case RDA1846_REG_SQ_SHUT: return "SQ_SHUT"; case RDA1846_REG_DTMF_CTL: return "DTMF_CTL"; case RDA1846_REG_DTMF_T1: return "DTMF_T1"; case RDA1846_REG_DTMF_T2: return "DTMF_T2"; case RDA1846_REG_DTMF_C01: return "DTMF_C01"; case RDA1846_REG_DTMF_C23: return "DTMF_C23"; case RDA1846_REG_DTMF_C45: return "DTMF_C45"; case RDA1846_REG_DTMF_C67: return "DTMF_C67"; case RDA1846_REG_DTMF_OUT: return "DTMF_OUT"; default: return "unknown"; } } void rda1846_dump_register(void) { printf("RDA1846: register dump\r\n"); const uint8_t regs[] = { RDA1846_REG_RF_BAND, RDA1846_REG_XTAL, RDA1846_REG_ADCLK, RDA1846_REG_CLK_MODE, RDA1846_REG_CTL, RDA1846_REG_INT, RDA1846_REG_GPIO, RDA1846_REG_TX_VOICE, RDA1846_REG_DTMF_CTL, RDA1846_REG_RSSI, RDA1846_REG_VSSI, RDA1846_REG_FLAG, RDA1846_REG_DTMF_OUT, RDA1846_REG_FREQH, RDA1846_REG_FREQL }; int i; for(i=0; i