Closed Gavin-Perry closed 1 year ago
I'm reading Datasheet 2.3.1.2. GPIO Control but would like help to be sure I get this right.
Thanks again
There might be a slightly faster way depending on the number of write ports on the GPIO block, but you'd need to ping the RPI Pico forums to get the HW designers' answer, but why not just use a mutex to protect GPIO accesses?
Define a shared global GPIO mutex:
auto_init_mutex(gpioMutex);
Then acquire the mutex before doing any atomic changes necessary:
mutex_enter_blocking(&gpioMutex);
<do all the GPIO changes on this core, including XOR, etc.>
mutex_exit(@gpioMutex);
Both cores' access to the GPIOs should use that same mutex. It will guarantee only one core at a time can modify GPIO state.
I'd also probably disable interrupts after taking the mutex (and before touching GPIOs), and re-enable them before exiting the mutex.
I don't know BLDC motor control, but if it is driven by a Gray code then only 1 bit will be XOR'd between steps so you could just write to that XOR register inside the mutex protection and avoid any glitching)
The data sheet provides links to the relevant SDK code so this is where the XOR write (aka toggle) function can be found, viz: https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_gpio/include/hardware/gpio.h#L710-L717
However, the GPIO operations are already atomic and made so at hardware level in the SIO block, so I suspect the problem is elsewhere in the code. Look at the duplicated code you mentioned and look for any shared (global) variables that the two processors are sharing, this is likely where the problem is. Post the code if you cannot spot the problem.
Earle, you have done an amazing job. I so much appreciate being able to stick with Arduino IDE even when using SDK routines.
My program was working great (driving a BLDC motor) until I duplicated the code to run a second motor on the second processor. From the RP2040 Datasheet I read: Each peripheral register block is allocated 4kB of address space, with registers accessed using one of 4 methods, selected by address decode. • Addr + 0x0000 : normal read write access • Addr + 0x1000 : atomic XOR on write • Addr + 0x2000 : atomic bitmask set on write • Addr + 0x3000 : atomic bitmask clear on write
I've been using simple Arduino routines digitalRead() and digitalWrite() if (digitalRead(BURSTPB1_PIN)==LOW) { // button pressed delay(20); // Plenty of debounce time for old buttons while(digitalRead(BURSTPB1_PIN)==LOW); // Wait for button release to do it // DO a step motion ... Here is the actual step: rather crudely implemented but it worked (with just one motor) byte Pos2Coils[6] = {5,4,6,2,3,1}; // Array of bits for motor phases to do one rotation ..... newPos2 = Pos2Coils[mod(Position2,6)]; // next position (0-5) if (bitRead(newPos2,0)) digitalWrite(CM2A,HIGH); else digitalWrite(CM2A,LOW); if (bitRead(newPos2,1)) digitalWrite(CM2B,HIGH); else digitalWrite(CM2B,LOW); if (bitRead(newPos2,2)) digitalWrite(CM2C,HIGH); else digitalWrite(CM2C,LOW); I should probably gather all three bits and then put them out together but not knowing how (except in assembler) I punted.
The problem is Motor 1 stops when motor 2 runs in certain conditions. I'd use bitWrite() but it wants: x: the numeric variable to which to write. n: which bit of the number to write, starting at 0 for the least-significant (rightmost) bit. b: the value to write to the bit (0 or 1). No clue what to put for a GPIO pin. Pins may or may not even be in the same byte since I just assigned them sequentially for easy PCB layout. I'd rather not have to respin the PCB to line up the bits.
Is there a way to do the atomic XOR write in Arduino? (SDK call?) How do I know if (or avoid) the 2 processors in contention?
There are delayMicroseconds() after every step, but that's not doing it. DoStep(CHAN); // Move the selected motor one phase step delayMicroseconds(1000000/speed);
Thanks for your help (or anyone else that has done this)
Gavin