Migrate Function from PIC to Particle

I have a function below that I need to convert to function in the same way as on the Pic but I am not able to get it done. The function should generate a 40KHz signal. Can somebody pls support me? Thanks!

static void GeneratePulse(uint16 uwPulseWidth, BOOLEAN bBipolar)
{
    /* Control command for ultrasonic sender set to LOW */
    output_bit(PIN_ULTRA_A, LOW);
    output_bit(PIN_ULTRA_B, LOW);
    
    /* Start PWM-Output for ultrasonic burst  */
    setup_ccp1(CCP_PWM);
    set_timer_period_ccp1(399);     // 40 KHz
    set_ccp1_compare_time(200);

    if (bBipolar == TRUE)
    {
        setup_ccp2(CCP_PWM);
        set_timer_period_ccp2(399); // 40 KHz
        set_ccp2_compare_time(200);
    }

    set_timer_ccp1(0);              // PWM resetten
    set_timer_ccp2(200);
    set_timer1(0);                  // [4µs]
    
    /* Wait until ultrasonic burst is created */
    while (get_timer1() < (uwPulseWidth / 4))
    {
        ;
    }
    
    /* Stop PWM-Output */
    setup_ccp1(CCP_OFF);
    setup_ccp2(CCP_OFF);

    /* Control command for ultrasonic sender set to LOW */
    output_bit(PIN_ULTRA_A, LOW);
    output_bit(PIN_ULTRA_B, LOW);  
}

Not the same thing and limited to available PWM pins:
Have you tried the custom PWM frequency via analogWrite()?

Yes I did and also

for(int i = 0; i < 100; i++)
         {
             digitalWrite(PIN_ULTRA_A, HIGH);
             digitalWrite(PIN_ULTRA_B, LOW);
             delayMicroseconds(12.5);
             digitalWrite(PIN_ULTRA_A, LOW);
             digitalWrite(PIN_ULTRA_B, HIGH);
             delayMicroseconds(12.5); 
         }

I tried different loop iterations but that did not work as expected.

Hmm, still not the bare metal solution you may be looking for but when I do this, the result doesn’t seem too wrong to me

const boolean bBipolar = true;

void d0ISR() 
{
    int v = pinReadFast(D1);
    digitalWriteFast(D0, !v);
    digitalWriteFast(A0, v);    // optional for better synchronicity D0/A0 vs. D0/D1
}

void setup() 
{
    pinMode(D1, OUTPUT);
    if (bBipolar) 
    {
      pinMode(D0, OUTPUT);
      pinMode(A0, OUTPUT);      // optional for better synchronicity D0/A0 vs. D0/D1
      attachInterrupt(D1, d0ISR, CHANGE);
    }
    analogWrite(D1, 128, 40000);
}

If you can allow for a about 2µs overlap between the two channels you can get away with just D0/D1.

Sure bare metal would be better, but why go down that rabbit hole when not needed.

Yeah that seems to work better.

The same struggle is for the other way round to read the values with ADC. I got the function:

static void MeasureSignal(void)
{
    uint16 uwAdc, uwCnt;   
    
    memset(&gauwSamples, 0, NUM_SAMPLES * 2); // Abtastwerte auf Null setzen
    
    /* Read AD-values */
    for (uwCnt = 0; uwCnt < NUM_SAMPLES; uwCnt++)
    {
        output_bit(PIN_PAD1, HIGH);    
        uwAdc = read_adc(ADC_START_AND_READ);
        output_bit(PIN_PAD1, LOW);        
        gauwSamples[uwCnt] = uwAdc;
        delay_cycles(120);    // Sampling rate 58us --> Difference between two sample values
                              // results in the distance difference from the measurement object 
                              // of 1cm
    }
}

I tried it with the following:

void MeasureSignal(void)
{
    int uwAdc, uwCnt;

    memset(&gauwSamples, 0, NUM_SAMPLES * 2);

    for (uwCnt = 0; uwCnt < NUM_SAMPLES; uwCnt++)
    {
        uwAdc = analogRead(PIN_US_READ);
        gauwSamples[uwCnt] = uwAdc;
        setADCSampleTime(ADC_SampleTime_112Cycles);
    }
}

Do you also have a better idea for this?

setADCSampleTime(ADC_SampleTime_112Cycles) only needs to be called once to set that sample time and IIRC analogRead() does take 10 samples for averaging already.

But if you explaned what the problem with your code was (what did you expect vs. what did you get) advising might be more fruitful :wink:

Sure. So with the MeasureSignal the sent ultrasonic waves from generate pulse should be read and with another function find the maximum the measure the distance from the sensors to an object. The problem is that the distance should be outputted absolutely in cm and with the PIC it works. Also with the oscillator I can see the maximum very well. But as described I can not get it to work with the firmware and read out the maximum and I think the problem are those 2 functions everything else should be fine.

@mojo90, in the PIC code you have output_bit(PIN_PAD1, HIGH); and output_bit(PIN_PAD1, LOW); but you didn’t put these in the Particle version. Any reason?

BTW, one ADC cycle on the Photon is 33.3ns. A setting of ADC_SampleTime_112Cycles will do a conversion in 3.73us. Based on what your comments indicate regarding the 58us per sample, you would need to inject a delayMicroseconds(54); to get the timing closer to what the PIC is doing.

        delay_cycles(120);    // Sampling rate 58us --> Difference between two sample values
                              // results in the distance difference from the measurement object 
                              // of 1cm

Yeah that was just for debugging reasons.

Thank you for that information! I inserted that. But in the MeasureSignal that read_adc(ADC_START_AND_READ) is not the same as analogRead(PIN_US_READ) isn’t it? Is there something similar where I can continous read ADC with a sample rate rather than just once? I think that is at the moment the problem