Mercurial > ~darius > hgwebdir.cgi > modulator
changeset 8:0249d0cecac4
Use interpolator to compute pulse up.
Use interpolator to clamp values.
Calculate speed.
Do memory clear in routine to be more honest about the speed.
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Sun, 16 Feb 2025 14:36:33 +1030 |
parents | 4ad473648949 |
children | 3acdebd7eec7 |
files | modulator.c |
diffstat | 1 files changed, 84 insertions(+), 43 deletions(-) [+] |
line wrap: on
line diff
--- a/modulator.c Sun Feb 16 10:09:05 2025 +1030 +++ b/modulator.c Sun Feb 16 14:36:33 2025 +1030 @@ -73,7 +73,7 @@ } // Calculate pulse shape data -// TODO: sense, gate, phase, active, T/R switch +// TODO: predistortion, proper sense, gate, phase, active, T/R switch // Could encode them as bit stream like data but more compact would be // (say) a list of counts to toggle pins at #define SENSE 0x01 @@ -89,7 +89,40 @@ char tmps[20]; interp_config cfg; - // Setup lane 0 to generate index into shape table + if (ncode == 1) { + // Number of samples for half of the pulse + // Do division first so we don't overflow Q16.16 + shapesamples = qtoi(qmul(qdiv(qint(plen), qint(100)), qint(shapelen / 2))); + // Number of samples for everything + // XXX: Need the +1 otherwise slew2 is truncated + nsamples = shapesamples * 2 + slew1 + slew2 + 1; + } else { + shapesamples = plen / 2; + nsamples = shapesamples * 2 * ncode + codegap * (ncode - 1) + slew1 + slew2 + 1; + } + + // Number of steps per samples in the pulse shape + stepsize = qdiv(qint(shapelen), qint(shapesamples)); + qsprint(stepsize, tmps, sizeof(tmps)); + printf("shapelen = %d shapesamples = %lu nsamples = %lu stepsize = %s\n", shapelen, shapesamples, nsamples, tmps); + + // Check the requested pulse will not overflow given data + if (nsamples > datalen) { + printf("Pulse too long (%ld > %u)\n", nsamples, datalen); + return 0; + } + // Check it is not too short + if (shapesamples < 2) { + printf("Pulse too short (%lu < %d)\n", shapesamples, 2); + return 0; + } + // Or too long (will overflow for loop variable) + if (qtoi(shapesamples) > 65535) { + printf("Shape too long (%u > %d)\n", qtoi(shapesamples), 65535); + return 0; + } + + // Setup interp 0 lane 0 to generate index into shape table // Mask start is 0 because we use 8 bit samples cfg = interp_default_config(); interp_config_set_shift(&cfg, QBITS); @@ -97,48 +130,32 @@ interp_config_set_blend(&cfg, true); interp_set_config(interp0, 0, &cfg); - // Setup lane 1 to LERP each sample pair + // Setup interp 0 lane 1 to LERP each sample pair cfg = interp_default_config(); interp_config_set_shift(&cfg, QBITS - 8); interp_config_set_signed(&cfg, false); interp_config_set_cross_input(&cfg, true); // unsigned blending interp_set_config(interp0, 1, &cfg); + // Setup interp 1 lane 0 to clamp 0-255 + cfg = interp_default_config(); + interp_config_set_clamp(&cfg, true); + interp_config_set_shift(&cfg, 0); + interp_config_set_mask(&cfg, 0, 8); + interp_config_set_signed(&cfg, false); + interp_set_config(interp1, 0, &cfg); + interp1->base[0] = 0; + interp1->base[1] = 255; + interp0->accum[0] = 0; // Initial offset into shape table interp0->base[2] = (uintptr_t)shape; // Start of shape table - dcscale = qdiv(qsub(qint(255), qint(dcofs)), qint(255)); + dcscale = qdiv(qsub(qint(256), qint(dcofs)), qint(255)); qsprint(dcscale, tmps, sizeof(tmps)); printf("dcscale = %s\n", tmps); - if (ncode == 1) { - // Number of samples for half of the pulse - // Do division first so we don't overflow Q16.16 - shapesamples = qtoi(qmul(qdiv(qint(plen), qint(100)), qint(shapelen / 2))); - // Number of samples for everything - nsamples = shapesamples * 2 + slew1 + slew2; - } else { - shapesamples = plen / 2; - nsamples = shapesamples * 2 * ncode + codegap * (ncode - 1) + slew1 + slew2; - } - - // Number of samples per step in the pulse shape - stepsize = qdiv(qint(shapesamples), qint(shapelen)); - qsprint(stepsize, tmps, sizeof(tmps)); - printf("shapelen = %d shapesamples = %lu nsamples = %lu stepsize = %s\n", shapelen, shapesamples, nsamples, tmps); - - if (nsamples > datalen) { - printf("Pulse too long (%ld > %u)\n", nsamples, datalen); - return 0; - } - if (shapesamples < 2) { - printf("Pulse too short (%lu < %d)\n", shapesamples, 2); - return 0; - } - if (qtoi(shapesamples) > 65535) { - printf("Shape too long (%u > %d)\n", qtoi(shapesamples), 65535); - return 0; - } + memset(pulse_data, 0, sizeof(pulse_data)); + memset(pulse_ctrl, 0, sizeof(pulse_ctrl)); idx = 0; // Up slew @@ -155,10 +172,24 @@ ctrltmp |= PHINV; // Pulse up + if (c == 0) { + interp0->accum[0] = 0; // Initial offset into shape table + interp0->base[2] = (uintptr_t)shape; // Start of shape table + } for (uint16_t i = 0; i < shapesamples; i++) { - if (c == 0) - data[idx++] = dcofs + qtoi(qmul(qint(shape[qtoi(qdiv(qint(i), stepsize))]), dcscale)); - else + if (c == 0) { + // Get sample pair + uint8_t *sample_pair = (uint8_t *) interp0->peek[2]; + // Ask lane 1 for a LERP, using the lane 0 accumulator + interp0->base[0] = sample_pair[0]; + interp0->base[1] = sample_pair[1]; + uint8_t peek = interp0->peek[1]; + // Apply DC offset scaling & clamp + interp1->accum[0] = dcofs + qtoi(qmul(qint(peek), dcscale)); + data[idx++] = interp1->peek[0]; + // Update interpolator for next point + interp0->add_raw[0] = stepsize; + } else // Already done it before, just copy the previous instance data[idx++] = data[bit1startup + i]; ctrl[idx] = ctrltmp; @@ -167,6 +198,9 @@ bit1stopup = idx - 1; // Pulse down // Since the pulse is symmetrical just copy the up slope in reverse + // XXX: if we had asymmetrical predistortion this wouldn't be true + // In that case probably best to do a single pulse up/down, then + // add predistortion and copy it to other bits for (uint16_t i = 0; i < shapesamples; i++) { data[idx++] = data[bit1stopup - i]; // Could replace this with a separate loop to poke it into place @@ -186,7 +220,7 @@ } // Down slew - for (uint16_t i = 0; i < slew2; i++) { + for (uint16_t i = 0; i < slew2 + 1; i++) { data[idx++] = qtoi(qdiv(qmul(qint(dcofs), qint(slew2 - i)), qint(slew2))); ctrl[idx] |= PACTIVE; } @@ -258,15 +292,20 @@ //interp_test(pulse_data, shaped_trap); uint32_t idx; - uint16_t plen = 4000; - char *code = "1110010"; - //char *code = "10"; + uint16_t plen; + char *code; + if (0) { + plen = 8000; + code = "1110010"; + } else { + plen = 53000; + code = "1"; + } + uint8_t codegap = 4; uint8_t slew1 = 10; uint8_t slew2 = 10; uint8_t dcofs = 110; - memset(pulse_data, 0, sizeof(pulse_data)); - memset(pulse_ctrl, 0, sizeof(pulse_ctrl)); then = get_absolute_time(); if ((idx = compute_pulse(pulse_data, pulse_ctrl, sizeof(pulse_data), plen, code, strlen(code), @@ -277,8 +316,10 @@ ; } now = get_absolute_time(); - printf("Pulse computation took %lld usec and created %lu samples\n", absolute_time_diff_us(then, now), idx); - + unsigned long long diff = absolute_time_diff_us(then, now); + printf("Pulse computation took %lld usec and created %lu samples - %.1f nsec/sample\n", + diff, idx, (float)diff * 1000.0 / idx); + __breakpoint(); pwm_config c = pwm_get_default_config(); // 120MHz / 250 = 480kHz base // Maximum divisor is only 256 which limits the low end,