Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for hardware versions. Added NeoPixel. #175 #181

Closed
wants to merge 0 commits into from

Conversation

SmittyHalibut
Copy link
Collaborator

@SmittyHalibut SmittyHalibut commented Jan 20, 2025

ESP32:

Added firmware support for:

  • Detecting hardware versions.
    • Note: Sense_V[PN] pins don't have internal pull-[up|down] resistors, so the intended method of detecting versions won't work. Hi-Z reads the same as LOW. Really, it means that we've gone from 9 detectable versions to only 4. One of those versions will have to specify another method of detecting, probably using different GPIO pins. Anyway. For now, we're ok.
  • Added support for NeoPixel. Radio's state (stopped, Tx, Rx with squelch open, or closed) are now indicated on the NeoPixel by color.
  • Fixed: v2.0 moved the Squelch pin to a different GPIO. Now that we can detect the hardware version, this is now fixed and the code looks in the right place.

PCB

  • Easier to solder, larger pads on the 818.
  • Added ADC auto bias from DAC2 (see [ESP32] Fine tune the ADC bias voltage #180 and related)
  • Cleaned up some unused outlines.
  • Spread apart Reset and Program buttons so my fat sausage fingers and press them both.

@VanceVagell
Copy link
Owner

Please merge with main, resolve conflicts (mainly around how firmware determines VHF/UHF), and test. When I did that, I get this error (seen in serial output from the ESP32):

Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.

It then crashes and restarts the firmware, this happens on a loop.

@SmittyHalibut
Copy link
Collaborator Author

SmittyHalibut commented Jan 21, 2025

Please merge with main, resolve conflicts (mainly around how firmware determines VHF/UHF)

Done.

...and test. When I did that, I get this error (seen in serial output from the ESP32):

Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.

It then crashes and restarts the firmware, this happens on a loop.

Are you seeing this when just connected to a terminal emulator? Or is there a way to see what's coming over serial in the app?

SmittyHalibut added a commit to SmittyHalibut/kv4p-ht that referenced this pull request Jan 21, 2025
@SmittyHalibut
Copy link
Collaborator Author

Please merge with main, resolve conflicts (mainly around how firmware determines VHF/UHF), and test. When I did that, I get this error (seen in serial output from the ESP32):

Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.

It then crashes and restarts the firmware, this happens on a loop.

What do you see on the phone app when this happens? I've got it saying "No firmware installed." Is that what you're seeing? I'm just trying to confirm whether I'm chasing a phantom or not.

@VanceVagell
Copy link
Owner

Yes, it says no firmware installed (because the ESP32 isn't replying to the GET_VERSION command). To further investigate I reviewed the Arduino IDE terminal with the ESP32 connected and see the error I included above. I've never seen that error before, so I suspect it's something in this PR.

@@ -730,3 +832,52 @@ void processTxAudio(uint8_t tempBuffer[], int bytesRead) {
bytesToWrite -= bytesWritten;
} while (bytesToWrite > 0);
}

uint8_t get_hardware_version() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems too complicated to what it does. Is it effectively the same to the:

uint8_t get_hardware_version() {
  pinMode(HW_VER_0_PIN, INPUT_PULLDOWN); pinMode(HW_VER_1_PIN, INPUT_PULLDOWN);
  uint8_t down = (digitalRead(HW_VER_1_PIN) << 1) | digitalRead(HW_VER_0_PIN);
  pinMode(HW_VER_0_PIN, INPUT_PULLUP); pinMode(HW_VER_1_PIN, INPUT_PULLUP);
  uint8_t up = (digitalRead(HW_VER_1_PIN) << 1) | digitalRead(HW_VER_0_PIN);
  return (down == up) ? down : 0xFF; // Return version or error
}

And if there no pull-ups support on those pins, we can do:

uint8_t get_hardware_version() {
  pinMode(HW_VER_0_PIN, INPUT_PULLDOWN); pinMode(HW_VER_1_PIN, INPUT_PULLDOWN);
  return (digitalRead(HW_VER_1_PIN) << 1) | digitalRead(HW_VER_0_PIN);
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized the "no pull-[up|down]" thing as I was filing the PR, after already making all the changes. You're right that this can be WAY simpler now. I'm just kicking myself for not looking at this before releasing v2.0c into the wild. sigh

@SmittyHalibut
Copy link
Collaborator Author

SmittyHalibut commented Jan 22, 2025

I've confirmed I'm fighting the fact that I don't have the most current app version on my phone. That means I have to setup the Google app development environment, which I don't have the time to do today. I've already spent longer on this PR than I intended today.

On the plus side, all my new code: NeoPixels, Hardware Versions, and the new SoftwareSerial console I've put on the GPIO header, are all #ifdef wrapped now so it should be a bit easier to narrow down where the problem is. I've also got another serial console I can write to for printf() debugging (my favorite!)

Yeah, I just confirmed that comms are stuck at getting a firmware version. I can't debug anymore without the current app version. This will have to be later.

EDIT: Oh, look, that's what you just said 13 minutes ago: #181 (comment)

Ok, so that is the same thing you're seeing. I'll dig a little more, but I didn't touch the serial protocol handling.

I did notice that at the top of loop(), you're just counting 8 characters without actually testing that they're the delimiter characters. This is likely to get things out of sync. So I added a couple lines that reset bytesRead if the byte read wasn't the correct byte, by comparing it against COMMAND_DELIMITER[bytesRead]. In my debugging, it looks like it's correctly detecting the delimiter, reading the command byte, going into the COMMAND_GET_FIRMWARE_VER block, then dies while trying to parse which band this module is on. I suspect yours is dying before this point, because I know mine is dying here because the App is not sending the right parameters.

@@ -524,18 +613,26 @@ void loop() {
size_t samplesRead = bytesRead / 2;

bool squelched = (digitalRead(SQ_PIN) == HIGH);
if (first_time) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it’s probably a good idea to extract the LED control and pixel operations into a separate function like displayUserFeedback(). Something like:


enum Mode {
  MODE_STOPPED,
  MODE_RX_OPEN,
  MODE_RX_CLOSED,
  MODE_TX
};

void displayUserFeedback(Mode mode) {
  switch (mode) {
    case MODE_STOPPED:
      digitalWrite(LED_PIN, LOW);
      digitalWrite(PTT_PIN, HIGH);
      pixels.setPixelColor(0, COLOR_STOPPED);
      break;
    case MODE_RX_OPEN:
      digitalWrite(LED_PIN, LOW);
      pixels.setPixelColor(0, COLOR_RX_SQL_OPEN);
      break;
    case MODE_RX_CLOSED:
      digitalWrite(LED_PIN, LOW);
      pixels.setPixelColor(0, COLOR_RX_SQL_CLOSED);
      break;
    case MODE_TX:
      digitalWrite(LED_PIN, HIGH);  // LED ON for TX
      pixels.setPixelColor(0, COLOR_TX);
      break;
    default:
      break;
  }

  pixels.show();
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. After doing all the #ifdef stuff, I was very quickly regretting doing it all inline and not abstracting it out. Now that I'm re-doing it all, I will do it better.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done in #207

// Setup NeoPixel for debugging.
#define PIXELS_NUM 1
#define PIXELS_PIN 13
Adafruit_NeoPixel pixels(PIXELS_NUM, PIXELS_PIN, NEO_GRB + NEO_KHZ400);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to unit and call NeoPixels conditionally? For specific hardware revisions? Or turn on/off in settings?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, absolutely. Doing it for specific hardware revisions isn't necessary since it doesn't hurt to squirt NeoPixel colors into a disconnected GPIO pin. But allowing the user to disable the LEDs in software definitely makes sense. I'll make that easier to do.

@@ -166,7 +245,12 @@ void initI2SRx() {

// Initialize ADC
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_12);
if (hardware_version == HW_V2_0C) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is better approach to change it in settings?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why's that? This is a hardware dependent change, dependent on where the bias voltage has been set. v2.0c has a fixed bias at 0.56v, therefore requires a low output volume from the 818 so it doesn't clip into the negative, and therefore requires DB_0.

v2.0d uses your variable bias design and therefore should use the maximum signal to noise ratio design.

result = dra->volume(8);
if (hardware_version == HW_V2_0C) {
// v2.0c has a lower input ADC range.
result = dra->volume(4);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is better approach to change it in settings?

Copy link
Collaborator

@dkaukov dkaukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me with a few minor comments.

@VanceVagell, I believe features like VHF/UHF, NeoPixel support, volume, attenuation, etc., should be implemented in a consistent way. There are two possible approaches:

  • The firmware automatically detects and sets them up. (and possible sends the state in GetVersion reply, if needed)
  • The user can configure them through the Settings.

Feel free to merge or request further changes as you see fit.

Note: I personally prefer @SmittyHalibut’s approach of auto-detection, especially since we have plenty of ESP32 pins available. However, since you’ve started implementing the VHF/UHF switch in the settings, I wanted to raise this as a concern. ;) Also, I’d personally prefer to encode 'features' instead of board versions, but that’s just my take on it.

@SmittyHalibut
Copy link
Collaborator Author

Withdrawing this PR so I can split it into multiple smaller, easier to test, PRs. So far, see #199 and #201.

@SmittyHalibut
Copy link
Collaborator Author

@dkaukov I'm not ignoring your comments. As I rework the changes in #175 into smaller PRs, I'll be taking your comments into account. Thank you.

@SmittyHalibut
Copy link
Collaborator Author

Note: I personally prefer @SmittyHalibut’s approach of auto-detection, especially since we have plenty of ESP32 pins available. However, since you’ve started implementing the VHF/UHF switch in the settings, I wanted to raise this as a concern. ;) Also, I’d personally prefer to encode 'features' instead of board versions, but that’s just my take on it.

The only reason that VHF/UHF is implemented as a user option is because the SA818s don't report which band they are. There's no way to auto-detect this from the SA818 module. We could implement a way to specify at assemble time: jumper here for VHF, there for UHF. shrug That's not a horrible idea.

@dkaukov
Copy link
Collaborator

dkaukov commented Jan 28, 2025

Hi @SmittyHalibut,

This is exactly what I mean! For example, we could short GPIO12 to ground to indicate UHF, and include the VHF/UHF info in the VersionInfo reply so the Android app can switch automatically. Similarly, shorting GPIO13 to ground could indicate the presence of a NeoPixel. This way, we’re encoding hardware features directly instead of relying on board revisions. With all the spare ESP32 pins, it’s simple and makes it easier for you to mix and match features in future board designs!!

@SmittyHalibut
Copy link
Collaborator Author

With the expansion headers, there aren't as many "unused" pins as it seems. We can definitely reclaim some of those from the headers if we want/need. But there isn't a glut of unused pins. That's why I originally put the first two version detect on the Sense pins; they were the only two that weren't already assigned.

I think we'll run out of pins VERY quickly if we tried to make a pin for every feature. I believe we should keep with board versions. #myOpinion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants