| Products > Test Equipment |
| New bench scope - Fnirsi 1014D, 7", 1GSa/s |
| << < (51/67) > >> |
| pcprogrammer:
The way I worked with the scope while developing was having the special FEL boot on the SD card and use the sunxi-fel tool to load the fresh build code to test things. This way there is no wear on the SD card and the process has a quick turnaround. Don't worry about memory. There is 32MB and the code itself is very small. 229KB for the 1013D. It uses a chunk of the memory to store the screen data and buffers for the samples which is less then 4MB. (Did not check the actual amount). Adding extra code won't make it that much bigger. In Ghidra it is possible to de-compile to pseudo C, which makes things easier to read. But then still, it takes it's time to become an expert with it. A simple test you can do is to just setup channel 1 of the clock synth to generate 50MHz and see if the sampling starts to work. I'm quite sure they don't change this clock to adjust the sampling rate simply because the other parts of the FPGA design depend on this clock to be set at a fixed value. Channel 2 will be a different story. The pin assignments they did in the 1013D for the touch panel are another example of stupid. There is a two wire interface available on other pins of the MCU they could have used instead of bit banging. The same goes for the 1014D. The swapping of the SDA and SCL pins between the 1014D and 1013D design has to do with UART1. |
| pcprogrammer:
Damn you for raising my curiosity :-DD I did some measurements on the clock signals. As I suspected the main clock input is set at 50MHz and stays fixed on that. The other one varies with frequency settings of the AWG. The only thing is that I made an error in the schematic. CLK0 (pin 10) is for the AWG and CLK1 (pin 9) is for the main clock. The relation between the AWG frequency and the clock frequency looks a bit odd. For sine wave at 10MHz the clock is 200MHz and at 9MHz I measured 180MHz, but for 8MHz it went back up to 200MHz, so there is more to it then just controlling this clock. I have to say that I did not do accurate measurements. Just probed the signal with my big scope set to 10ns/div and frequency measurement on between two cursors. Due to DC offset and noise it was not very stable. It is probably easier to get the information from reverse engineering the code. I also found that I left my scope in FEL mode. When I booted it to do the measurements it stayed stuck on the boot screen, and both clock signals were off. I removed the SD card and it booted with "SD error" message. Now the clocks were running, both at 50MHz. I got another blank formatted SD card and it booted normally with the main clock at 50MHz and the other one very very low. Turned out the AWG was set to 0.005Hz :palm: So try to modify the startup of the 1013D code to write settings to the clock IC to set both channels to 50MHz before initializing the FPGA, and see if the sampling starts to work. |
| pcprogrammer:
I could not resist to take a peak at the code >:( In the Ghidra project there are two versions of the 1014D firmware, and in V3 I named two functions to be for the clock control I2C. The function more_i2c_stuff_for_fpga_clock takes two parameters, which I named setting1 and setting2. The function some_i2c_stuff_for_fpga_clock takes one parameter, which is a byte to be send out on the I2C bus. In the function more_i2c_stuff_for_fpga_clock it first sends 0xC0 followed by setting1 and setting2. Have not hold it against the datasheet of the clock ic. The other functions in the FPGA init function probably do some calculations on data to come to the setting bytes to be send to the clock ic. I uploaded a new archive to the repository. Edit: Renamed the functions and the parameters after looking at the datasheet. Confirmed that the 0xC0 is addressing the ic for write, followed by a register address and the data for it. So the two functions are the low level bit for writing a register in the ic. (Look for fpga_clock_ic in the Ghidra project 1014D_program_V3) Attached is the Ghidra C output for the two functions. |
| donwulff:
Whee, now we're doing duplicate work, like I said I've been looking at Ghidra ;) I was wondering if I should've posted the garbage that it decompiled, haha. But yeah I figured the basics, the actual register files not so much... But after the last post I was reading machine translation of the Chinese datasheet for the clock gen, until I discovered it's all explained in AN619 of the Silicon Labs chip https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/application-notes/AN619.pdf (Is it as simple as PLL 30 x 25 = 750MHz VCO / MS 30 = 50MHz? I'll find out!). Now that I understand the values bit better and know they're not magic, the register settings are starting to make a bit more sense to me. There's also Arduino library https://github.com/etherkit/Si5351Arduino which I'd forgotten about for directly calculating & setting the values dynamically, so could even just use that. I guess I shouldn't be surprised if the clocks are really distributed that way... There's an odd extra function called for the second clock, but other than that they look pretty symmetrical in code. (Function names random guessed of course). --- Code: ---void fpga_init(void) { uint *puVar1; uint uVar2; init_porta_0_1_output(); uVar2 = DAT_80017534; i2c_fpga_clockgen_ch0_reset(DAT_80017534); i2c_fpga_clockgen_ch1_reset(uVar2); i2c_fpga_clockgen_ch1_set(1); puVar1 = DAT_80017538; gpio_config_pin(DAT_80017538,9,1); --- End code --- Which is Ghidra being weird, because yes, both initial functions are called with the same parameter = 02FAF080h. Then the i2c_fpga_clockgen_ch0_reset() ends in: --- Code: ---LAB_80026220: if ((uVar3 <= uVar4) && (uVar4 = uVar3, uVar3 < uVar1)) { uVar4 = uVar1; } uVar1 = (uint)((ulonglong)uVar4 * (ulonglong)DAT_800262f8 >> 0x37); iVar6 = DAT_800262fc * uVar1; uVar5 = FUN_8003bd3c(uVar4 + iVar6 * 0x40,iVar6,DAT_800262fc, (int)((ulonglong)uVar4 * (ulonglong)DAT_800262f8)); uVar5 = FUN_8003bde8(uVar5,DAT_80026300); FUN_8003ba60(uVar5,DAT_80026304); uVar5 = FUN_8003bcb8(); i2c_fpga_clockgen_config_pll(0x1a,uVar1 & 0xff,uVar5,DAT_80026308); if (uVar2 < uVar7 - 0x9c4) { i2c_fpga_clockgen_config_ms(0x2a,4,0xc); } else { i2c_fpga_clockgen_config_ms(0x2a,unaff_r6,bVar8); } i2c_fpga_clockgen_reg(0xb1,0x20); ptr = DAT_8001e440; set_gpio_pin_high(DAT_8001e440,0); set_gpio_pin_high(ptr,1); set_gpio_pin_low(ptr,0); _delay(10); set_gpio_pin_low(ptr,1); _delay(10); _delay(10); i2c_fpga_clockgen_chg(0xc0); _delay(10); i2c_fpga_clockgen_chg(0x10); _delay(10); i2c_fpga_clockgen_chg(0x4f); _delay(10); set_gpio_pin_low(ptr,1); _delay(10); set_gpio_pin_low(ptr,0); _delay(10); set_gpio_pin_high(ptr,1); _delay(10); set_gpio_pin_high(ptr,0); delay(10); return; --- End code --- So we have a LOT of weird functions (possibly more before that point) with pointers for figuring out the values. We set the PLL divider and then the MultiSynth counters with out magic values. Register 0xb1 = 177 = PLL RESET, specifically PLLA here, which makes the new parameters take force. Then, for who knows what reason, we have the register setting protocol expanded out. Register 0x10 = 16 = CLK0 Control. Maximum 8 mA drive, clock from MultiSynth 0 in "integer mode" to improve jitter. Of note, none of this is actually going according to either the Silicon Labs or chinese datasheet. They have "disable output, power down output drivers" before divider settings and tell to use 177 = 0xAC to reset PLL. The second clock is handled in exactly the same way, only the register addresses seem to change for the second clock. But of course THEN we get the i2c_fpga_clockgen_ch1_set() which changes the MultiSynth values based on yet other functions... And looking again, i2c_fpaga_clockgen_ch0_reset is called again in relation to the scope, but I guess i2c_fpaga_clockgen_ch0_reset and i2c_fpaga_clockgen_ch0_set are never called again after initialization. Unknown function end: --- Code: --- fpga_write_cmd('G'); fpga_write_data((uchar)((*(ushort *)(iVar2 + 2) - 1) * 0x10000 >> 0x18)); fpga_write_data(*(char *)(iVar2 + 2) + 0xff); uVar13 = DAT_8001c128; uVar8 = *(uint *)(iVar2 + 4) * (uint)*(ushort *)(iVar2 + 2); if (DAT_8001c124 < uVar8) { uVar8 = DAT_8001c124; } if (*(uint *)(iVar2 + 4) < 10) { *(undefined *)(iVar2 + 0xb) = 1; if (uVar8 < 0xfa) { uVar8 = 0xfa; } i2c_fpga_clockgen_ch0_reset(uVar8 * 10); } else { *(undefined *)(iVar2 + 0xb) = 0; if (uVar8 < uVar13) { uVar8 = DAT_8001c128; } i2c_fpga_clockgen_ch0_reset(uVar8); } fpga_write_cmd('H'); fpga_write_data(*(uchar *)(iVar2 + 0xb)); if (*(int *)(iVar2 + 4) == 0) { fpga_write_cmd('F'); uVar13 = 0; do { fpga_write_data('c'); uVar13 = uVar13 + 1 & 0xfffeffff; } while (uVar13 < 1000); return; } fpga_write_cmd('F'); uVar13 = 0; do { fpga_write_data(pbVar3[uVar13]); uVar13 = uVar13 + 1 & 0xfffeffff; } while (uVar13 < 1000); return; --- End code --- None of those FPGA commands are in the https://github.com/pecostm32/FNIRSI-1013D-1014D-Hack/blob/main/FPGA%20explained/FPGA%20explained.txt document, so that's some more reverse engineering along with trying to find out what it does to the clock gen. And whoops, just re-read what you said with thought, so this must be for the clock-gen whereas the other, fixed output with extra function is indeed for the oscilloscope. No wonder I was thinking it was being changed! It seems like I might need a crash-course in Ghidra. I'm going to try to solve these BEFORE posting, though ;) EDIT: Oh yeah, also want to use FEL for all the reasons, but as complained before, libusb doesn't really work over Microsoft RDP RemoteFX USB pass-through. Or it does, if the USB device is part of a composite device and the software looks for that device directly and not the composite device... but yeah, let's just say it doesn't work until fixed. EDITn: Yes I also looked at how the Sipeed Lichee Nano with F1C100s has 16MB flash, so I guess the 1MB set aside for firmware on the SD-card is just a matter of choice and guessing it won't grow above that. It would also theoretically be possible to load different modules from SD into memory? Si5351A ClockBuilder Pro lets me choose 200MHz + 50MHz clock even though I guess it's way beyond spec (actually looks like it's in, but needs special settings). So this is something like what I should be looking for in the code. I wonder why there's so many functions & apparent dynamicity to the setting in FNIRSI, just stupid choice/ready-made library I guess? Also note you can write i2c in consequential manner, even according to the Chinese clone datasheet, no need to give write & register address for each. And most registers default to 0x00 value after reset, so those register writes can generally be ignored (unless needed to cover a gap in the register sequence), but that's on ClockBuilder Pro. Also, this dump shows I still really don't understand the register configuration. The math of "Fvco = 32 x 25MHz = 800MHz, CLK0 divider 4 = 200MHz, CLK1 divider 16 = 50MHz" is just as I'd expect, then in the register file... 0x00E00. WTAF ;) --- Code: ---/* * Si5351A Rev B Configuration Register Export Header File * * This file represents a series of Skyworks Si5351A Rev B * register writes that can be performed to load a single configuration * on a device. It was created by a Skyworks ClockBuilder Pro * export tool. * * Part: Si5351A Rev B * Design ID: * Includes Pre/Post Download Control Register Writes: Yes * Created By: ClockBuilder Pro v4.7 [2022-11-18] * Timestamp: 2023-01-06 18:41:46 GMT+02:00 * * A complete design report corresponding to this export is included at the end * of this header file. * */ #ifndef SI5351A_REVB_REG_CONFIG_HEADER #define SI5351A_REVB_REG_CONFIG_HEADER #define SI5351A_REVB_REG_CONFIG_NUM_REGS 53 typedef struct { unsigned int address; /* 16-bit register address */ unsigned char value; /* 8-bit register data */ } si5351a_revb_register_t; si5351a_revb_register_t const si5351a_revb_registers[SI5351A_REVB_REG_CONFIG_NUM_REGS] = { { 0x0002, 0x53 }, { 0x0003, 0x00 }, { 0x0004, 0x20 }, { 0x0007, 0x00 }, { 0x000F, 0x00 }, { 0x0010, 0x4F }, { 0x0011, 0x0F }, { 0x0012, 0x8C }, { 0x0013, 0x8C }, { 0x0014, 0x8C }, { 0x0015, 0x8C }, { 0x0016, 0x8C }, { 0x0017, 0x8C }, { 0x0018, 0x0A }, { 0x001A, 0x00 }, { 0x001B, 0x01 }, { 0x001C, 0x00 }, { 0x001D, 0x0E }, { 0x001E, 0x00 }, { 0x001F, 0x00 }, { 0x0020, 0x00 }, { 0x0021, 0x00 }, { 0x002A, 0x00 }, { 0x002B, 0x01 }, { 0x002C, 0x0C }, { 0x002D, 0x00 }, { 0x002E, 0x00 }, { 0x002F, 0x00 }, { 0x0030, 0x00 }, { 0x0031, 0x00 }, { 0x0032, 0x00 }, { 0x0033, 0x01 }, { 0x0034, 0x00 }, { 0x0035, 0x06 }, { 0x0036, 0x00 }, { 0x0037, 0x00 }, { 0x0038, 0x00 }, { 0x0039, 0x00 }, { 0x005A, 0x00 }, { 0x005B, 0x00 }, { 0x0095, 0x00 }, { 0x0096, 0x00 }, { 0x0097, 0x00 }, { 0x0098, 0x00 }, { 0x0099, 0x00 }, { 0x009A, 0x00 }, { 0x009B, 0x00 }, { 0x00A2, 0x00 }, { 0x00A3, 0x00 }, { 0x00A4, 0x00 }, { 0x00A5, 0x00 }, { 0x00A6, 0x00 }, { 0x00B7, 0x92 }, }; /* * Design Report * * Overview * ======== * Part: Si5351A * Created By: ClockBuilder Pro v4.7 [2022-11-18] * Timestamp: 2023-01-06 18:41:46 GMT+02:00 * * Design Rule Check * ================= * Errors: * - No errors * * Warnings: * - No warnings * * Design * ====== * I2C Address: 0x60 * * Inputs: * IN0: 25 MHz * * Outputs: * OUT0: 200 MHz * Enabled LVCMOS 8 mA * Offset 0.000 s * OUT1: 50 MHz * Enabled LVCMOS 8 mA * Offset 0.000 s * OUT2: Unused * * Frequency Plan * ============== * PLL_A: * Enabled Features = None * Fvco = 800 MHz * M = 32 * Input0: * Source = Crystal * Source Frequency = 25 MHz * Fpfd = 25 MHz * Load Capacitance = Load_08pF * Output0: * Features = None * Disabled State = HiZ * R = 1 (2^0) * Fout = 200 MHz * N = 4 * Output1: * Features = None * Disabled State = HiZ * R = 1 (2^0) * Fout = 50 MHz * N = 16 * * Settings * ======== * * Location Setting Name Decimal Value Hex Value * ------------ -------------- ----------------- ----------------- * 0x0002[3] XO_LOS_MASK 0 0x0 * 0x0002[4] CLK_LOS_MASK 1 0x1 * 0x0002[5] LOL_A_MASK 0 0x0 * 0x0002[6] LOL_B_MASK 1 0x1 * 0x0002[7] SYS_INIT_MASK 0 0x0 * 0x0003[7:0] CLK_OEB 0 0x00 * 0x0004[4] DIS_RESET_LOLA 0 0x0 * 0x0004[5] DIS_RESET_LOLB 1 0x1 * 0x0007[7:4] I2C_ADDR_CTRL 0 0x0 * 0x000F[2] PLLA_SRC 0 0x0 * 0x000F[3] PLLB_SRC 0 0x0 * 0x000F[4] PLLA_INSELB 0 0x0 * 0x000F[5] PLLB_INSELB 0 0x0 * 0x000F[7:6] CLKIN_DIV 0 0x0 * 0x0010[1:0] CLK0_IDRV 3 0x3 * 0x0010[3:2] CLK0_SRC 3 0x3 * 0x0010[4] CLK0_INV 0 0x0 * 0x0010[5] MS0_SRC 0 0x0 * 0x0010[6] MS0_INT 1 0x1 * 0x0010[7] CLK0_PDN 0 0x0 * 0x0011[1:0] CLK1_IDRV 3 0x3 * 0x0011[3:2] CLK1_SRC 3 0x3 * 0x0011[4] CLK1_INV 0 0x0 * 0x0011[5] MS1_SRC 0 0x0 * 0x0011[6] MS1_INT 0 0x0 * 0x0011[7] CLK1_PDN 0 0x0 * 0x0012[1:0] CLK2_IDRV 0 0x0 * 0x0012[3:2] CLK2_SRC 3 0x3 * 0x0012[4] CLK2_INV 0 0x0 * 0x0012[5] MS2_SRC 0 0x0 * 0x0012[6] MS2_INT 0 0x0 * 0x0012[7] CLK2_PDN 1 0x1 * 0x0013[1:0] CLK3_IDRV 0 0x0 * 0x0013[3:2] CLK3_SRC 3 0x3 * 0x0013[4] CLK3_INV 0 0x0 * 0x0013[5] MS3_SRC 0 0x0 * 0x0013[6] MS3_INT 0 0x0 * 0x0013[7] CLK3_PDN 1 0x1 * 0x0014[1:0] CLK4_IDRV 0 0x0 * 0x0014[3:2] CLK4_SRC 3 0x3 * 0x0014[4] CLK4_INV 0 0x0 * 0x0014[5] MS4_SRC 0 0x0 * 0x0014[6] MS4_INT 0 0x0 * 0x0014[7] CLK4_PDN 1 0x1 * 0x0015[1:0] CLK5_IDRV 0 0x0 * 0x0015[3:2] CLK5_SRC 3 0x3 * 0x0015[4] CLK5_INV 0 0x0 * 0x0015[5] MS5_SRC 0 0x0 * 0x0015[6] MS5_INT 0 0x0 * 0x0015[7] CLK5_PDN 1 0x1 * 0x0016[1:0] CLK6_IDRV 0 0x0 * 0x0016[3:2] CLK6_SRC 3 0x3 * 0x0016[4] CLK6_INV 0 0x0 * 0x0016[5] MS6_SRC 0 0x0 * 0x0016[6] FBA_INT 0 0x0 * 0x0016[7] CLK6_PDN 1 0x1 * 0x0017[1:0] CLK7_IDRV 0 0x0 * 0x0017[3:2] CLK7_SRC 3 0x3 * 0x0017[4] CLK7_INV 0 0x0 * 0x0017[5] MS7_SRC 0 0x0 * 0x0017[6] FBB_INT 0 0x0 * 0x0017[7] CLK7_PDN 1 0x1 * 0x0018[1:0] CLK0_DIS_STATE 2 0x2 * 0x0018[3:2] CLK1_DIS_STATE 2 0x2 * 0x001C[17:0] MSNA_P1 3584 0x00E00 * 0x001F[19:0] MSNA_P2 0 0x00000 * 0x001F[23:4] MSNA_P3 1 0x00001 * 0x002C[17:0] MS0_P1 0 0x00000 * 0x002C[2] MS0_DIVBY4_0 1 0x1 * 0x002C[3] MS0_DIVBY4_1 1 0x1 * 0x002F[19:0] MS0_P2 0 0x00000 * 0x002F[23:4] MS0_P4 1 0x00001 * 0x0034[17:0] MS1_P1 1536 0x00600 * 0x0037[19:0] MS1_P2 0 0x00000 * 0x0037[23:4] MS1_P4 1 0x00001 * 0x005A[7:0] MS6_P2 0 0x00 * 0x005B[7:0] MS7_P2 0 0x00 * 0x0095[14:0] SSDN_P2 0 0x0000 * 0x0095[7] SSC_EN 0 0x0 * 0x0097[14:0] SSDN_P3 0 0x0000 * 0x0097[7] SSC_MODE 0 0x0 * 0x0099[11:0] SSDN_P1 0 0x000 * 0x009A[15:4] SSUDP 0 0x000 * 0x00A2[21:0] VCXO_PARAM 0 0x000000 * 0x00A5[7:0] CLK0_PHOFF 0 0x00 * 0x00A6[7:0] CLK1_PHOFF 0 0x00 * 0x00B7[7:6] XTAL_CL 2 0x2 * * */ #endif --- End code --- |
| pcprogrammer:
Haha, I only looked at the lowest level of the code because I had already found those two functions before, but did not checked the parameters. I stopped after verifying that it was indeed addressing the clock chip. Looked at the programming of the clock ic just a little bit and decided it was up to you to dig further, which you did :) I uploaded the stuff I created in regards with the 1014D FPGA to the reversal repository. The commands in the 0x4X range are indeed unknown to me and chances are they have to do with the AWG. The clock synthesizer CLK0 output is the variable one. CLK1 is fixed on 50MHz, so verify that your findings match with this. The command 0x46 ('F') looks like the one for loading the waveform memory. It loops to write a 1000 bytes to the FPGA, which more or less matches the 1KB I found available for it in the FPGA reversal. Based on the measurements I did, I guess that with one of the other commands they set a clock divider and maybe a range of samples to use. |
| Navigation |
| Message Index |
| Next page |
| Previous page |