-
Notifications
You must be signed in to change notification settings - Fork 120
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
Added RH_ASK support for SAMD51 processor #58
base: master
Are you sure you want to change the base?
Conversation
Normally wouldn't open a PR if I didnt test but I'm hoping others with ASK radios will see it, right now there is no working RH_ASK to break for the SAMD51, and I validated the code I added works. |
@IoTPanic, I've tried ASK receiver testing to no avail. I ran the same code (based on the RadioHead ask_receiver example) on an Arduino UNO and the ItsyBitsy M4 Express. Using pin 11 for Rx. Used 5V to power the receiver in both cases. The UNO was able to receive, and the M4 was not. I used a 2:1 resistor voltage divider to protect the digital input of the M4; 2.5V should be enough to get a I was able to verify your new Arduino SAMD51 section of code was being called by inducing a compile error. I also verified that all code was executing normally except no bytes were ever received from the I'll continue to poke around a bit and perhaps get a transmitter hooked up and try the setup the other way around. Here's the receiver test code: // ask_receiver_test
// Use RadioHead to receive messages from a simple ASK transmitter.
// Implements a simplex (one-way) ASK receiver.
#include <RH_ASK.h>
#include <SPI.h> // Not actually used but needed to compile
RH_ASK driver(2000, 11); // 2000 bps, Rx on D11
// debug globals
bool failed = true;
bool gothere = false;
void setup()
{
delay(2000); // does not print startup messages without this delay
Serial.begin(19200);
if (driver.init()) {
failed = false;
Serial.println("init success");
} else {
failed = true;
Serial.println("init failed");
}
}
void loop()
{
uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
uint8_t buflen = sizeof(buf);
if (driver.recv(buf, &buflen)) {
gothere = true;
if (buflen>2) {
Serial.print(buflen);
Serial.print(" bytes: ");
for (int i=0; i<buflen-1; i++)
Serial.print((char)buf[i]);
Serial.println((char)buf[buflen-1]);
}
} else {
Serial.println("got nothing");
}
delay(500);
if (failed) {
Serial.println("failed");
} else {
Serial.print("waiting ");
Serial.println(buflen);
if (gothere) {
Serial.println("got there");
}
}
} All I get is
|
@IoTPanic, I'm looking at your You define I'm not clear on how the M4 timers work, but just poking around I found examples of setting up TC3 using |
@WunderBeard I started the fix by copying and pasting the M0 timer code since the two ICs are similar and GCLK0 is the main CPU clock, I chose this because in the past there has been issues with timer consistency in Arduino and if I used the CPU clock that is a known constant no matter what a users library setup is. I copied and pasted the code of this commit into a blank project, and tested that it works correctly. As long as you are using commit af749de it should work. A good next step may be to make a new global variable within |
Yes, but doesn't the prescaler need to be divided by 8 to get 8 interrupts per bit (line 263)? I can try to copy and paste to test the timer code independently (or try the global idea). |
@WunderBeard no, originally I used a by eight divider but in my testing the precision wasn't that good, in fact, I think the SAMD21 code needs to be updated to the same as I have it. |
@IoTPanic, I fixed it! I did the following changes: #elif defined (__arm__) && defined(__SAMD51__)
// Arduino SAMD51
#define RH_ASK_M4_TIMER TC3
// Clock speed is 120MHz, prescaler of 64 provides good precision (~0.53 us ticks)
#define RH_ASK_M4_PRESCALER 64
#define RH_ASK_M4_TIMER_IRQ TC3_IRQn
GCLK->PCHCTRL[TC3_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val |
(1 << GCLK_PCHCTRL_CHEN_Pos);
while (GCLK->SYNCBUSY.reg > 0); // wait for sync
RH_ASK_M4_TIMER->COUNT16.CTRLA.bit.ENABLE = 0;
RH_ASK_M4_TIMER->COUNT16.WAVE.bit.WAVEGEN = TC_WAVE_WAVEGEN_MFRQ;
while (RH_ASK_M4_TIMER->COUNT16.SYNCBUSY.reg != 0) {} // wait for sync
RH_ASK_M4_TIMER->COUNT16.INTENSET.reg = 0;
RH_ASK_M4_TIMER->COUNT16.INTENSET.bit.MC0 = 1;
// Enable IRQ
NVIC_EnableIRQ(RH_ASK_M4_TIMER_IRQ);
RH_ASK_M4_TIMER->COUNT16.CTRLA.reg &= ~0b011100000000; // clear PRESCALER[2:0]
while (RH_ASK_M4_TIMER->COUNT16.SYNCBUSY.reg != 0) {} // wait for sync
RH_ASK_M4_TIMER->COUNT16.CTRLA.reg |= (uint32_t)TC_CTRLA_PRESCALER_DIV64; // must match RH_ASK_M4_PRESCALER
while (RH_ASK_M4_TIMER->COUNT16.SYNCBUSY.reg != 0) {} // wait for sync
// Compute the count required to achieve the requested baud (with 8 interrupts per bit)
uint32_t rc = (VARIANT_MCK / _speed) / RH_ASK_M4_PRESCALER / 8;
RH_ASK_M4_TIMER->COUNT16.CC[0].reg = rc;
while (RH_ASK_M4_TIMER->COUNT16.SYNCBUSY.reg != 0) {} // wait for sync
RH_ASK_M4_TIMER->COUNT16.CTRLA.bit.ENABLE = 1;
while (RH_ASK_M4_TIMER->COUNT16.SYNCBUSY.reg != 0) {} // wait for sync I think DIV16 is an unnecessary amount of resolution (even though we have room in the counter for it). I think the fix was to divide by 8 so that you get the required 8 interrupts per bit for the configured bit rate. Thanks for all of your help with this! |
@WunderBeard you were not using commit af749de |
@IoTPanic, yes I was using your latest commit. What I'm saying is that I thought 16 was waaay too much resolution. Who needs 0.13 us resolution when 0.53 us will work just fine? So I changed it back to 64. If you insist, it still works just fine if you plug in 16 as the prescaler. The bug is on line 263. You must divide the ticks by 8 to get 8 interrupts per bit time. |
@WunderBeard I would like it to be kept to DIV16, but honestly it does not matter, if the prescaler is smaller its just more precision with no consequence. I just pushed a new commit, could you test that for me if you checkout (c73f900)? Thank you for repeating the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works with my ASK receiver.
Awesome! Thank you so much for the help @WunderBeard! |
Fix to issue #28 which I will reclose once this has been at least tested working. I made a logical test with M4 ItsyBitsy to my change and the timer code works well, I just don't have a ASK radio to test it on so if someone could verify that would be great.
Issue
Issue was that compiling for RH_ASK failed due to commit #29 that remove the C definitions of RH_ASK since none of the library would compile without it.
Solution
I added the correct timer code for the SAMD51 along with IRQ handler