/* -------------------------------------------------------------------------------------------------- */ /* The LongMynd receiver: stv0910.c */ /* - an implementation of the Serit NIM controlling software for the MiniTiouner Hardware */ /* - the demodulator support routines (STV0910) */ /* Copyright 2019 Heather Lomond */ /* -------------------------------------------------------------------------------------------------- */ /* This file is part of longmynd. Longmynd 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 (at your option) any later version. Longmynd 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 longmynd. If not, see . */ /* -------------------------------------------------------------------------------------------------- */ /* ----------------- INCLUDES ----------------------------------------------------------------------- */ /* -------------------------------------------------------------------------------------------------- */ #include #include #include #include "stv0910.h" #include "stv0910_regs.h" #include "stv0910_utils.h" #include "nim.h" #include "errors.h" #include "stv0910_regs_init.h" /* -------------------------------------------------------------------------------------------------- */ /* ----------------- ROUTINES ----------------------------------------------------------------------- */ /* -------------------------------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_car_freq(uint8_t demod, int32_t *cf) { /* -------------------------------------------------------------------------------------------------- */ /* reads the current carrier frequency and return it (in Hz) */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* car_freq: signed place to store the answer */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; uint8_t val_h, val_m, val_l; double car_offset_freq; /* first off we read in the carrier offset as a signed number */ err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_CFR2 : RSTV0910_P1_CFR2, &val_h); /* high byte*/ if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_CFR1 : RSTV0910_P1_CFR1, &val_m); /* mid */ if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_CFR0 : RSTV0910_P1_CFR0, &val_l); /* low */ /* since this is a 24 bit signed value, we need to build it as a 24 bit value, shift it up to the top to get a 32 bit signed value, then convert it to a double */ car_offset_freq=(double)(int32_t)((((uint32_t)val_h<<16) + ((uint32_t)val_m<< 8) + ((uint32_t)val_l )) << 8); /* carrier offset freq (MHz)= mclk (MHz) * CFR/2^24. But we have the extra 256 in there from the sign shift */ /* so in Hz we need: */ car_offset_freq=135000000*car_offset_freq/256.0/256.0/256.0/256.0; *cf=(int32_t)car_offset_freq; if (err!=ERROR_NONE) printf("ERROR: STV0910 read carrier frequency\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_constellation(uint8_t demod, uint8_t *i, uint8_t *q) { /* -------------------------------------------------------------------------------------------------- */ /* reads an I,Q pair from the constellation monitor registers */ /* i,q: places to store the results */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_ISYMB : RSTV0910_P1_ISYMB, i); if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_QSYMB : RSTV0910_P1_QSYMB, q); if (err!=ERROR_NONE) printf("ERROR: STV0910 read constellation\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_sr(uint8_t demod, uint32_t *found_sr) { /* -------------------------------------------------------------------------------------------------- */ /* reads the currently detected symbol rate */ /* found_sr: place to store the result */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ double sr; uint8_t val_h, val_mu, val_ml, val_l; uint8_t err; err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_SFR3 : RSTV0910_P1_SFR3, &val_h); /* high byte */ if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_SFR2 : RSTV0910_P1_SFR2, &val_mu); /* mid upper */ if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_SFR1 : RSTV0910_P1_SFR1, &val_ml); /* mid lower */ if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_SFR0 : RSTV0910_P1_SFR0, &val_l); /* low byte */ sr=((uint32_t)val_h << 24) + ((uint32_t)val_mu << 16) + ((uint32_t)val_ml << 8) + ((uint32_t)val_l ); /* sr (MHz) = ckadc (MHz) * SFR/2^32. So in Symbols per Second we need */ sr=135000000*sr/256.0/256.0/256.0/256.0; *found_sr=(uint32_t)sr; if (err!=ERROR_NONE) printf("ERROR: STV0910 read symbol rate\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_puncture_rate(uint8_t demod, uint8_t *rate) { /* -------------------------------------------------------------------------------------------------- */ /* reads teh detected viterbi punctuation rate */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* rate: place to store the result */ /* The single byta, n, represents a rate=n/n+1 */ /* return: error code */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; uint8_t val; err=stv0910_read_reg_field(demod==STV0910_DEMOD_TOP ? FSTV0910_P2_VIT_CURPUN : FSTV0910_P1_VIT_CURPUN, &val); switch (val) { case STV0910_PUNCTURE_1_2: *rate=1; break; case STV0910_PUNCTURE_2_3: *rate=2; break; case STV0910_PUNCTURE_3_4: *rate=3; break; case STV0910_PUNCTURE_5_6: *rate=5; break; case STV0910_PUNCTURE_6_7: *rate=6; break; case STV0910_PUNCTURE_7_8: *rate=7; break; default: err=ERROR_VITERBI_PUNCTURE_RATE; break; } if (err!=ERROR_NONE) printf("ERROR: STV0910 read puncture rate\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_power(uint8_t demod, uint8_t *power_i, uint8_t *power_q) { /* -------------------------------------------------------------------------------------------------- */ /* reads the power registers in the Demodulator and returns the results */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* power_i, power_q: places to store the results */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; /*power=1/4.ADC */ err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_POWERI : RSTV0910_P1_POWERI, power_i); if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_POWERQ : RSTV0910_P1_POWERQ, power_q); if (err!=ERROR_NONE) printf("ERROR: STV0910 read power\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_err_rate(uint8_t demod, uint32_t *vit_errs) { /* -------------------------------------------------------------------------------------------------- */ /* reads the viterbi error rate registers */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* vit_errs: place to store the result */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; uint8_t val; err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_VERROR : RSTV0910_P1_VERROR, &val); /* 0=perfect, 0xff=6.23 %errors (errs/4096) */ /* note there is a problem in the datasheet here as it says 255/2048=6.23% */ /* to report an integer we will report in 100 * the percentage, so 623=6.23% */ /* also want to round up to the nearest integer just to be pedantic */ *vit_errs=((((uint32_t)val)*100000/4096)+5)/10; if (err!=ERROR_NONE) printf("ERROR: STV0910 read viterbi error rate\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_ber(uint8_t demod, uint32_t *ber) { /* -------------------------------------------------------------------------------------------------- */ /* reads the number of bytes processed by the FEC, the number of error bits and then calculates BER */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* ber: place to store the result */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; uint8_t high, mid_u, mid_m, mid_l, low; double cpt; double errs; /* first we trigger a buffer transfer and read the byte counter 40 bits */ err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_FBERCPT4 : RSTV0910_P1_FBERCPT4, &high); if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_FBERCPT3 : RSTV0910_P1_FBERCPT3, &mid_u); if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_FBERCPT2 : RSTV0910_P1_FBERCPT2, &mid_m); if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_FBERCPT1 : RSTV0910_P1_FBERCPT1, &mid_l); if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_FBERCPT0 : RSTV0910_P1_FBERCPT0, &low); cpt=(double)high*256.0*256.0*256.0*256.0 + (double)mid_u*256.0*256.0*256.0 + (double)mid_m*256.0*256.0 + (double)mid_l*256.0 + (double)low; /* we have already triggered the register buffer transfer, so now we we read the bit error from them */ err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_FBERERR2 : RSTV0910_P1_FBERERR2, &high); if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_FBERERR1 : RSTV0910_P1_FBERERR1, &mid_m); if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_FBERERR0 : RSTV0910_P1_FBERERR0, &low); errs=(double)high*256.0*256.0 + (double)mid_m*256.0 + (double)low; *ber=(uint32_t)(10000.0*errs/(cpt*8.0)); if (err!=ERROR_NONE) printf("ERROR: STV0910 read BER\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_mer(uint8_t demod, uint32_t *mer) { /* -------------------------------------------------------------------------------------------------- */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* mer: place to store the result */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; uint8_t high, low; err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_NOSRAMPOS : RSTV0910_P1_NOSRAMPOS, &high); if (err==ERROR_NONE) err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_NOSRAMVAL : RSTV0910_P1_NOSRAMVAL, &low); if(((high >> 2) & 0x01) == 1) { /* Px_NOSRAM_CNRVAL is valid */ *mer = ((high & 0x03) << 8) | low; } else { *mer = 0; if (err==ERROR_NONE) err=stv0910_write_reg_field(demod==STV0910_DEMOD_TOP ? FSTV0910_P2_NOSRAM_ACTIVATION : FSTV0910_P1_NOSRAM_ACTIVATION, 0x02); } if (err!=ERROR_NONE) printf("ERROR: STV0910 read DVBS2 MER\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_errors_bch_uncorrected(uint8_t demod, bool *errors_bch_uncorrected) { /* -------------------------------------------------------------------------------------------------- */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read*/ /* errors_bch_uncorrected: place to store the result */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; uint8_t result; /* This parameter appears to be total, not for an individual demodulator */ (void)demod; err=stv0910_read_reg_field(FSTV0910_ERRORFLAG, &result); if(result == 0) { *errors_bch_uncorrected = true; } else { *errors_bch_uncorrected = false; } if (err!=ERROR_NONE) printf("ERROR: STV0910 read BCH Errors Uncorrected\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_errors_bch_count(uint8_t demod, uint32_t *errors_bch_count) { /* -------------------------------------------------------------------------------------------------- */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* errors_bch_count: place to store the result */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; uint8_t result; /* This parameter appears to be total, not for an individual demodulator */ (void)demod; err=stv0910_read_reg_field(FSTV0910_BCH_ERRORS_COUNTER, &result); *errors_bch_count = (uint32_t)result; if (err!=ERROR_NONE) printf("ERROR: STV0910 read BCH Errors Count\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_errors_ldpc_count(uint8_t demod, uint32_t *errors_ldpc_count) { /* -------------------------------------------------------------------------------------------------- */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* errors_ldpc_count: place to store the result */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; uint8_t high, low; /* This parameter appears to be total, not for an individual demodulator */ (void)demod; err=stv0910_read_reg_field(FSTV0910_LDPC_ERRORS1, &high); if (err==ERROR_NONE) err=stv0910_read_reg_field(FSTV0910_LDPC_ERRORS0, &low); *errors_ldpc_count = (uint32_t)high << 8 | (uint32_t)low; if (err!=ERROR_NONE) printf("ERROR: STV0910 read LDPC Errors Count\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_modcod_and_type(uint8_t demod, uint32_t *modcod, bool *short_frame, bool *pilots) { /* -------------------------------------------------------------------------------------------------- */ /* Note that MODCODs are different in DVBS and DVBS2. Also short_frame and pilots only valid for S2 */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* modcod: place to store the result */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; uint8_t regval; err=stv0910_read_reg(demod==STV0910_DEMOD_TOP ? RSTV0910_P2_DMDMODCOD : RSTV0910_P1_DMDMODCOD, ®val); *modcod = (regval & 0x7c) >> 2; *short_frame = (regval & 0x02) >> 1; *pilots = regval & 0x01; if (err!=ERROR_NONE) printf("ERROR: STV0910 read MODCOD\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_setup_clocks() { /* -------------------------------------------------------------------------------------------------- */ /* sequence is: */ /* DIRCLK=0 (the hw clock selection pin) */ /* RESETB (the hw reset pin) transits from low to high at least 3ms after power stabilises */ /* disable demodulators (done in register initialisation) */ /* standby=1 (done in register initialisation) */ /* set NCOURSE etc. (PLL regs, also done in reg init) */ /* STANDBY=0 (turn on PLL) */ /* SYNCTRL:BYPASSPLLCORE=0 (turn on clocks) */ /* wait for lock bit to go high */ /* return: error code */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err=ERROR_NONE; uint32_t ndiv; uint32_t odf; uint32_t idf; uint32_t f_phi; uint32_t f_xtal; uint8_t cp; uint8_t lock=0; uint16_t timeout=0; printf("Flow: STV0910 set MCLK\n"); /* 800MHz < Fvco < 1800MHz */ /* Fvco = (ExtClk * 2 * NDIV) / IDF */ /* (400 * IDF) / ExtClk < NDIV < (900 * IDF) / ExtClk */ /* ODF forced to 4 otherwise desynchronization of digital and analog clock which result */ /* in a bad calculated symbolrate */ odf=4; /* IDF forced to 1 : Optimal value */ idf=1; if (err==ERROR_NONE) err=stv0910_write_reg_field(FSTV0910_ODF, odf); if (err==ERROR_NONE) err=stv0910_write_reg_field(FSTV0910_IDF, idf); f_xtal=NIM_TUNER_XTAL/1000; /* in MHz */ f_phi=135000000/1000000; ndiv=(f_phi * odf * idf) / f_xtal; if (err==ERROR_NONE) err=stv0910_write_reg_field(FSTV0910_N_DIV, ndiv); /* Set CP according to NDIV */ cp=7; if (err==ERROR_NONE) err=stv0910_write_reg_field(FSTV0910_CP, cp); /* turn on all the clocks */ if (err==ERROR_NONE) err=stv0910_write_reg_field(FSTV0910_STANDBY, 0); /* derive clocks from PLL */ if (err==ERROR_NONE) err=stv0910_write_reg_field(FSTV0910_BYPASSPLLCORE, 0); /* wait for PLL to lock */ do { timeout++; if (timeout==STV0910_PLL_LOCK_TIMEOUT) { err=ERROR_DEMOD_PLL_TIMEOUT; printf("ERROR: STV0910 pll lock timeout\n"); } if (err==ERROR_NONE) stv0910_read_reg_field(FSTV0910_PLLLOCK, &lock); } while ((err==ERROR_NONE) && (lock==0)); if (err!=ERROR_NONE) printf("ERROR: STV0910 set MCLK\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_setup_equalisers(uint8_t demod) { /* -------------------------------------------------------------------------------------------------- */ /* 2 parts DFE, FFE */ /* DFE: update speed is in EQUALCFG.PX_MU_EQUALDFE. */ /* turn it on with EQUAL_ON and freeze with PX_MU_EQUALDFE=0 */ /* FFE: update speed is in FFECFGPX_MU_EQUALFFE. */ /* turn it on with EQUALFFE_ON and freeze with PX_MU_EQUALFFE=0 */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* return: error code */ /* -------------------------------------------------------------------------------------------------- */ printf("Flow: Setup equlaizers %i\n", demod); return ERROR_NONE; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_setup_carrier_loop(uint8_t demod) { /* -------------------------------------------------------------------------------------------------- */ /* 3 stages: */ /* course: */ /* CARFREQ sets speed and precision */ /* limitsd are in CFRUP and CFRLOW */ /* step size in CFRINC */ /* fine: */ /* CARFREQ_BETA_FREQ defines time constant */ /* once course is done, phase tracking loop is used, ACLC and BCLC define loop parameters */ /* if DVBS not resolved, attempts to reolve DVB-S2 headers as defined in CARHDR.K_FREQ_HDR */ /* tracking: */ /* seperate alpha a beta for DVBS (ACLC and BCLC) and DVB-S2 (Alpha in CLC2S2Q and */ /* beta in ACLC2S28) */ /* lock detect: */ /* DVBS LDI has accumulator. compared to threshold (LDT, LDT2) and the results are */ /* in DSTATUS.CAR_LOCK */ /* when lock bit is set, freq detector is disabled amd starts phase tracking. */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* return: error code */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; printf("Flow: Setup carrier loop %i\n", demod); /* start at 0 offset */ err=stv0910_write_reg((demod==STV0910_DEMOD_TOP ? RSTV0910_P2_CFRINIT0 : RSTV0910_P1_CFRINIT0), 0); if (err==ERROR_NONE) err=stv0910_write_reg((demod==STV0910_DEMOD_TOP ? RSTV0910_P2_CFRINIT1 : RSTV0910_P1_CFRINIT1), 0); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_setup_timing_loop(uint8_t demod, uint32_t sr) { /* -------------------------------------------------------------------------------------------------- */ /* coarse aquisition */ /* put in coarse mode in TMGCFG2 (regs init) */ /* put in auto mode TMGCFG3 (regs init) */ /* set SFRUPRATIO, SFTLOWRATIO (regs init) */ /* set so that when boundary reached scan is inverted (regs init) */ /* set to keep looking indefinitely (regs init) */ /* DVBS alpha and beta are used */ /* observe where it is at with KREFTMG2 */ /* fine aquisition */ /* coarse search defines the fine scanning range automtically */ /* go to fine mode TMGCFG2 */ /* SFRSTEP.SFR_SCANSTEP defines fineness of scan */ /* tracking */ /* it now loads loop parameters */ /* seperate alphas and betas for DVBS and SVB-S2: */ /* DVBS TMGALPHA_EXP TIMGBETA_EXP in RTC */ /* iDVB-S2 TMGALPHAS2_EXP and TMGBETA2_EXP in RTCS2 */ /* when lock achieved timing offset is in TMGREG */ /* timing offset can be cancelled out (ie TMGREG set to zero and SFR adjusted accordingly */ /* */ /* lock indicator is DSTATUS maximised when locked. */ /* need to optimise lock thresholds to optimise lock stability */ /* lock indicator is filtered with time constant: TMGCFG.TMGLOCK_BETA */ /* this is compared to 2 thresholds TMGTHRISE_TMGLOCK_THRISE and TMGTHFALL.TMGLOCK_THFALL in order */ /* to issue TMGCLOCK_QUALITY[1:0] which is a 2 bit lock indicator with hysterisis in DSTATUS. */ /* lock is when TMGLOCK>TMGLOCK_THRISE (in TMGLOCK_QUALITY) */ /* loss of lock is when TMGLOCK < TTMGLOCK_THFALL in TMGLOCK_QUALITY */ /* */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err=ERROR_NONE; uint16_t sr_reg; printf("Flow: Setup timing loop %i\n", demod); /* SR (MHz) = ckadc (135MHz) * SFRINIT / 2^16 */ /* we have sr in KHz, ckadc in MHz) */ sr_reg=(uint16_t)((((uint32_t)sr) << 16) / 135 / 1000); if (err==ERROR_NONE) err=stv0910_write_reg((demod==STV0910_DEMOD_TOP ? RSTV0910_P2_SFRINIT1 : RSTV0910_P1_SFRINIT0), (uint8_t)(sr_reg >> 8) ); if (err==ERROR_NONE) err=stv0910_write_reg((demod==STV0910_DEMOD_TOP ? RSTV0910_P2_SFRINIT0 : RSTV0910_P1_SFRINIT1), (uint8_t)(sr_reg & 0xFF) ); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_setup_ts(uint8_t demod) { /* -------------------------------------------------------------------------------------------------- */ /* format with or without sync and header bytes TSINSDELH */ /* output rate manual or auto adjust */ /* control with TSCFX */ /* serial or paralled TSCFGH.PxTSFIFO_SERIAL (serial is on D7) 2 control bits */ /* configure bus to low impedance (high Z on reset) OUTCFG */ /* DPN (data valid/parity negated) is high when FEC is outputting data */ /* low when redundant data is out[ut eq parity data or rate regulation stuffing bits) */ /* Data is regulated by CLKOUT and DPN: either data valid or envelope. */ /* data valid uses continuous clock and select valid data using DPN */ /* envelope: DPN still indicates valid data and then punctured clock for rate regulation */ /* TSCFGH.TSFIFO_DVBCI=1 for data and 0 for envelope. */ /* CLKOUT polarity bit XOR, OUTCFG2.TS/2_CLKOUT_XOR=0 valid rising (=1 for falling). */ /* TSFIFOMANSPEED controlls data rate (padding). 0x11 manual, 0b00 fully auto. speed is TSSPEE */ /* if need square clock, TSCFGH.TSFIFO_DUTY50. */ /* parallel mode is ST back end. CLKOUT held (TSCFGH.TSINFO_DBCI) for unknown data section */ /* or DVB-CI: DRN is help (CLKOUTnCFG.CLKOUT_XOR) for unknown data section */ /* in both STRUT is high for first byte of packet */ /* rate compensation is TSCFGH.TSFIFO_DVBCI */ /* */ /* All of this is set in the register init. */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err=ERROR_NONE; printf("Flow: Setup ts %i\n", demod); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_start_scan(uint8_t demod) { /* -------------------------------------------------------------------------------------------------- */ /* demodulator search sequence is: */ /* setup the timing loop */ /* setup the carrier loop */ /* set initial carrier offset CFRINIT for best guess carrier search */ /* set initial symbol ratea SFRINIT for best guess blind search */ /* set manual mode for CFRINC to be used - make it small */ /* write DMDISTATE to AER = 1 - blind search with best guess */ /* auto mode for symbol rate will be +/25% SFRUPRATIO and SFRLOWRATIO define this number. */ /* SFRUP1:AUTO_GUP=1 for auto (and SFRLOW1:AUTO_GLOW=1) */ /* cold start carrier and sr unknown but use best guess (0x01) */ /* */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err=ERROR_NONE; printf("Flow: STV0910 start scan\n"); if (err==ERROR_NONE) err=stv0910_write_reg((demod==STV0910_DEMOD_TOP ? RSTV0910_P2_DMDISTATE : RSTV0910_P1_DMDISTATE), STV0910_SCAN_BLIND_BEST_GUESS); if (err!=ERROR_NONE) printf("ERROR: STV0910 start scan\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_read_scan_state(uint8_t demod, uint8_t *state) { /* -------------------------------------------------------------------------------------------------- */ /* simply reads out the demodulator states for the given demodulator */ /* demod: STV0910_DEMOD_TOP | STV0910_DEMOD_BOTTOM: which demodulator is being read */ /* return: error state */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err=ERROR_NONE; if (err==ERROR_NONE) err=stv0910_read_reg_field((demod==STV0910_DEMOD_TOP ? FSTV0910_P2_HEADER_MODE : FSTV0910_P1_HEADER_MODE), state); if (err!=ERROR_NONE) printf("ERROR: STV0910 read scan state\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_init_regs() { /* -------------------------------------------------------------------------------------------------- */ /* reads all the initial values for all the demodulator registers and sets them up */ /* return: error code */ /* -------------------------------------------------------------------------------------------------- */ uint8_t val1; uint8_t val2; uint8_t err; uint16_t i=0; printf("Flow: stv0910 init regs\n"); /* first we check on the IDs */ err=nim_read_demod(0xf100, &val1); if (err==ERROR_NONE) err=nim_read_demod(0xf101, &val2); printf(" Status: STV0910 MID = 0x%.2x, DID = 0x%.2x\n", val1, val2); if ((val1!=0x51) || (val2!=0x20)) { printf("ERROR: read the wrong stv0910 MID/DID"); return ERROR_DEMOD_INIT; } /* next we initialise all the registers in the list */ do { if (err==ERROR_NONE) err=stv0910_write_reg(STV0910DefVal[i].reg, STV0910DefVal[i].val); } while (STV0910DefVal[i++].reg!=RSTV0910_TSTTSRS); /* finally (from ST example code) reset the LDPC decoder */ if (err==ERROR_NONE) err=stv0910_write_reg(RSTV0910_TSTRES0, 0x80); if (err==ERROR_NONE) err=stv0910_write_reg(RSTV0910_TSTRES0, 0x00); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t stv0910_init(uint32_t sr1, uint32_t sr2) { /* -------------------------------------------------------------------------------------------------- */ /* demodulator search sequence is: */ /* setup the carrier loop */ /* set initial carrier offset CFRINIT for best guess carrier search */ /* set manual mode for CFRINC to be used - make it small */ /* setup the timing loop */ /* set initial symbol rate SFRINIT */ /* auto mode for symbol rate will be +/25% SFRUPRATIO and SFRLOWRATIO define this number. */ /* SFRUP1:AUTO_GUP=1 for auto (and SFRLOW1:AUTO_GLOW=1) */ /* write DMDISTATE to AER = 1 - blind search with best guess (SR and carrier unknown) */ /* FLYWHEEL_CPT: when 0xf DVB-S2 is locked in DMDFLYW (also int stus bits */ /* sr_top : the symbol rate to initialise the top demodulator to (0=disable) */ /* sr_bottom: the symbol rate to initialise the bottom demodulator to (0=disable) */ /* return: error code */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err=ERROR_NONE; printf("Flow: STV0910 init\n"); /* first we stop the demodulators in case they are already running */ if (err==ERROR_NONE) err=stv0910_write_reg(RSTV0910_P1_DMDISTATE, 0x1c); if (err==ERROR_NONE) err=stv0910_write_reg(RSTV0910_P2_DMDISTATE, 0x1c); /* do the non demodulator specific stuff */ if (err==ERROR_NONE) err=stv0910_init_regs(); if (err==ERROR_NONE) err=stv0910_setup_clocks(); /* now we do the inits for each specific demodulator */ if (sr1!=0) { if (err==ERROR_NONE) err=stv0910_setup_equalisers(STV0910_DEMOD_TOP); if (err==ERROR_NONE) err=stv0910_setup_carrier_loop(STV0910_DEMOD_TOP); if (err==ERROR_NONE) err=stv0910_setup_timing_loop(STV0910_DEMOD_TOP, sr1); } if (sr2!=0) { if (err==ERROR_NONE) err=stv0910_setup_equalisers(STV0910_DEMOD_BOTTOM); if (err==ERROR_NONE) err=stv0910_setup_carrier_loop(STV0910_DEMOD_BOTTOM); if (err==ERROR_NONE) err=stv0910_setup_timing_loop(STV0910_DEMOD_BOTTOM, sr2); } if (err!=ERROR_NONE) printf("ERROR: STV0910 init\n"); return err; }