Skip to content

Commit 30012b1

Browse files
committed
,
1 parent f6c014c commit 30012b1

File tree

14 files changed

+677
-501
lines changed

14 files changed

+677
-501
lines changed

megaavr/libraries/Event/README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,16 @@ Below is a table with all of the event users for the tinyAVR 0/1/2-series parts
170170
pinless: The parts potentially (per pinout) have this many event channels that can't be connected to any port's event generator
171171

172172

173+
`*` Likely AB-CD-EF
173174

174175
The tinyAVR 0/1-series layouts are really weird. See the documentation included with megaTinyCore for the table; 0-series don't have any RTC-PIT options, and 1-series has them all crowded onto one channel; both of them have two kinds of channels, and are generally a lot less flexible. The tinyAVR 2-series, on the other hand, is almost normal - except they have a better layout - (channels 0/1 get PA, PB, 2/3 get PC, PA and the last 2 get PB, PC. It's unclear how EA will be handled, Taken at face value the EA's product brief implies 6 channels in the standard layout, for 2 channels per port. 14-pin AVR-DD will have only 2 pins in PORTA (and with no portB, those 2 pins have channels 0 and 1 to themselves), and with no port E either, the 14 and 20pin parts will have only the two pins on PORTF, which are not going to be everyone's first choice for I/O (PF6 and PF7 are Reset and UPDI), so channels 4 and 5 are nearly pinless - assuming that what's in the headers pre-release is what they will ship. There is room for improvement, though it's really not bad.
175176

176177

177178
## Okay, so how do I read the state of these event channels?
178-
All you can do is use it for something that you can detect the response of. Yes, this is bizarre. They're already syncingh it for the sync subchannel! Use that to feed a register
179+
You don't? Even though each channel on the 2-series supposedly has a synchronizer on it, they for some reason didn't pipe those synchronized bits to a register that we could read from software, that would seem to be the natural thing to do. I'm not sure why, or whether there was a well-reasoned decision making process around this, or it was simply an oversight. An argument can certainly be made "what are you doing reading it from software?" (to which the obvious answer is "Because it's not working and I'm trying to figure out why").
180+
181+
The best you can do is pipe the outputs to a pin and read the pin....
182+
179183

180184
## The Event class
181185
Class for interfacing with the Event system (`EVSYS`). Each event channel has its own object.
@@ -207,6 +211,7 @@ These class methods return a reference to an event channel (an Event&), or Event
207211
| Event::assign_generator() | gen::generator_ | return channel that has that generator,<br/> pick one and set if none currently set |
208212
| Event::assign_generator_pin() | uint8_t | return channel that has that pin as generator,<br/> pick one and set if none currently set |
209213

214+
210215
Class methods for working with users or looking up generator or user numbers
211216
| Class Method | Argument Types | |
212217
|----------------------------------|------------------------------|--------------------------------------------------|
@@ -345,7 +350,7 @@ Event0.soft_event(); // Create a single software event on Event0
345350
### long_soft_event()
346351
soft_event() is only one system clock long. Often you need something a little longer. 2 clocks? 4 clocks maybe? Maybe it needs to get past the 'filter' on a CCL... Or you've got 2 things that need to happen a fraction of a microsecond apart; you've tried triggering one on the rising edge of a soft_event and the other on the falling edge, but it's just a hair too fast, and the other obvious solutions aren't viable due to the specifics of your scheme. The only way that a soft-event can last multiple system clocks is if the register is written every clock cycle. There is no time for a loop; only brute force (ie, a contiguous block of 'ST'ore instructions) will do the trick. Now in many ways this defeats the point of the event system; however, there are times when it is not entirely unreasonable to do this (as noted above), particularly if doing weird things with the CCLs, event system, and other peripherals.
347352

348-
The lengths that are available are 2, 4, 6, 10 and 16 (any number less than 4 will give 2 clock-long pulse, only 4 will give a 4 clock long one. Anything between 4 and 10 will give 6, exactly 10 will give 10, and anything larger will give 16). Those numbers were chosen based on perceived usefulness while staying within reason. The wacky rounding is a function of the way I cut clock cycles. [It's a block of 16 consecutive st instructions, prior to that, the code (in asm) checks the argument against 4. I then use a breq and a brmi. If you need longer, you shouold definitely use a different approach.
353+
The lengths that are available are 2, 4, 6, 10 and 16 (any number less than 4 will give 2 clock-long pulse, only 4 will give a 4 clock long one. Anything between 4 and 10 will give 6, exactly 10 will give 10, and anything larger will give 16). Those numbers were chosen arbitrarily to keep the size small, and give a selection that covered the reasonable use cases I could think of. If you need longer, you shouold definitely use a different approach.
349354

350355
#### Usage
351356
```c++
@@ -355,6 +360,11 @@ Event0.long_soft_event(10); // will invert the state of the event channel for 10
355360
```
356361
Don't forget that this is an invert, not a "high" or "low". It should be entirely possible for the event that normally drives it to occur resulting in the state changing during that pulse, depending on it's configuration. Note also that the overhead of long_soft_event is typically several times the length of the pulse due to calculating the bitmask to write; it's longer with higher numbered channels. if that is a problem, whatever your use case is, it is not one of the ones this was intended for...
357362

363+
#### Usage
364+
```c++
365+
Event0.soft_event(); // Create a single software event on Event0
366+
```
367+
358368
### start()
359369
Starts an event generator channel by writing the generator selected by `set_generator()` method to the `EVSYS.CHANNELn` register.
360370

@@ -400,7 +410,7 @@ Shown below, generators/user per instance (second argument should be less than
400410
401411
`*` - the tiny1 parts with 1 AC work normally. This is unfortunately not supported for tiny1 parts with the triple-AC configuration:
402412
`**` - There is only one CCL peripheral, with multiple logic blocks. Each logic block has 1 event generator and 2 event users. If using the logic library, get the Logic instance number. The output generator is that number. The input is twice that number, and twice that number + 1.
403-
`***` - This peripheral is not supported by t6his function, as the the generator numbers are channel dependent. Only effects aging parts anyway (though not that they do;t have some worthy features)
413+
`***` - This peripheral is not supported because the generator numbers are channel dependent.
404414
405415
`!` - These parts do have an option, but we didn't bother to implement it because it isn't particularly useful. But the Event RX mode combined with the TX input to the CCL permit arbitrary remapping of RX and very flexible remapping of TX.
406416

megaavr/libraries/Event/src/Event.cpp

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,8 @@ Event& Event::get_generator_channel(uint8_t generator_pin)
197197
uint8_t gen = 0xFF;
198198
if (port != NOT_A_PIN && port_pin != NOT_A_PIN) {
199199
#if defined(PORTA_EVGENCTRL)
200-
#error "what the f?"
201200
volatile PORT_t* port_ptr = portToPortStruct(port);
202-
uint8_t temp = port_ptr.EVGENCTRL;
201+
uint8_t temp = port_ptr->EVGENCTRL;
203202
if ((temp & 0x0F) == port_pin) {
204203
gen = 0x40 + (port << 1);
205204
_SWAP(port_pin);
@@ -834,19 +833,35 @@ int8_t Event::set_user_pin(uint8_t pin_number) {
834833
int8_t event_user = -1;
835834
if (port != NOT_A_PIN && port_pin != NOT_A_PIN) {
836835
#if !defined(TINY_0_OR_1_SERIES)
837-
/* Woah, we were missing a huge optimization opportunity here....
836+
/* Woah, we were missing a huge optimization opportunity here.... but only for DA/DB-series parts
838837
- The users are numbered in the same orderas the ports.
839838
- PA is #defined as 0, PB as 2, etc.
840839
- there are no parts for which a port exists that has a pin 2 or 7, but which does not allow that pin to be used as an event output, except for tiny 0/1, where only pin 2 is an option...
841840
We basically **don't have to test the port** as long as it's a valid port as we just tested. This is probably like 6-8 instructions instead of several dozen */
842841

843-
uint8_t evout_user = (int8_t) event::user::evouta_pin_pa2;
844-
if (port_pin == 2) { //non-0/1 pin 2 handling
845-
event_user = (evout_user + port);
846-
} //non-0/1 pin 7 handling
847-
else if (port_pin == 7) {
848-
event_user = (0x80 | (evout_user + port));
849-
}
842+
#if !defined(__AVR_DD__)
843+
uint8_t evout_user = (int8_t) event::user::evouta_pin_pa2;
844+
if (port_pin == 2) { //non-0/1 pin 2 handling
845+
event_user = (evout_user + port);
846+
} //non-0/1 pin 7 handling
847+
else if (port_pin == 7) {
848+
event_user = (0x80 | (evout_user + port));
849+
}
850+
#else
851+
uint8_t evout_user = -1;
852+
if (port_pin == 7 || port_pin == 2) {
853+
evout_user = port_pin == 7 ? 0x89 : 0x09;
854+
}
855+
if (port >= PC) {
856+
port--; // PA = 0 PC = 1, PD = 2, PF = 3
857+
if (port == PE) {
858+
port--; // We decremented port once already if it was >= PC, so the last valid port, PF now is PE.
859+
}
860+
}
861+
if (port <= PD) {
862+
event_user = evout_user + port;
863+
}
864+
#endif
850865
#else // Ugh, it's a 0/1-series....
851866
if (port_pin == 2) {
852867
#if defined (PIN_PB2)
@@ -863,7 +878,7 @@ int8_t Event::set_user_pin(uint8_t pin_number) {
863878
#else // No PIN_PB2, meaning it could only be an 8-pin tiny, and the only evout pin there is PA2.
864879
event_user = (int8_t) event::user::evouta_pin_pa2;
865880
#endif
866-
} // end if (port_pin==2)
881+
} // end if (port_pin==2)
867882
#endif // end 0/1-series
868883
else {
869884
return -1;
@@ -1035,7 +1050,7 @@ void Event::soft_event() {
10351050
#endif
10361051
}
10371052

1038-
static void __attribute__((unused)) _long_soft_event(uint8_t channel, uint8_t length); // holds the bulky assembly routine for the long softevent.
1053+
static void __attribute__((__unused__)) _long_soft_event(uint8_t channel, uint8_t length); // holds the bulky assembly routine for the long softevent.
10391054

10401055
void Event::long_soft_event(uint8_t length) {
10411056
_long_soft_event(channel_number, length);
@@ -1110,7 +1125,7 @@ event::gen::generator_t Event::gen_from_peripheral(__attribute__((unused))TCB_t&
11101125
#if defined(TINY_0_OR_1_SERIES)
11111126
badCall("gen_from_peripheral() does not support channel-specific generators. The TCBs on 0/1-series are.");
11121127
#else
1113-
#if !(defined(DXCORE) || defined(TINY_2_SERIES)) // Dx-series and 2-series have ovf event. Others dont.
1128+
#if !(defined(DXCORE) || defined(TINY_2_SERIES)) // Dx-series and 2-series have ovf event. Others don't.
11141129
if (event_type != 1) {
11151130
return (event::gen::generator_t) -1;
11161131
} else {

megaavr/libraries/Event/src/Event.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* set_generator(uint8_t pin_number) - to handle to more complicated setup of pin generators.
2121
*
2222
*/
23-
23+
/* *INDENT-OFF* */
2424
class Event {
2525
public:
2626
Event(uint8_t channel_num, volatile uint8_t &channel_addr);
@@ -34,7 +34,7 @@ class Event {
3434
void set_generator(uint8_t pin_number);
3535
static Event& assign_generator_pin(uint8_t port, uint8_t port_pin);
3636
static Event& assign_generator_pin(uint8_t pin_number);
37-
// *INDENT-OFF*
37+
3838
#if defined(TINY_0_OR_1_SERIES)
3939
void get_generator_channel(event::gens::generator_t generator) {
4040
get_generator_channel((event::gen::generator_t)generator);
@@ -52,7 +52,7 @@ class Event {
5252
#endif
5353
// *INDENT-ON*
5454
static int8_t get_user_channel_number(event::user::user_t event_user);
55-
static Event& get_user_channel(event::user::user_t event_user);
55+
static Event &get_user_channel(event::user::user_t event_user);
5656
void set_user(event::user::user_t event_user);
5757
int8_t set_user_pin(uint8_t pin_number);
5858
static void clear_user(event::user::user_t event_user);
@@ -61,14 +61,14 @@ class Event {
6161
void start(bool state = true);
6262
void stop();
6363
/* event_types: They start from 0x00 for inputs. Outputs start at 0x40 */
64-
static event::gen::generator_t gen_from_peripheral(TCB_t& timer, uint8_t event_type = 0);
65-
static event::user::user_t user_from_peripheral(TCB_t& timer, uint8_t user_type = 0);
66-
static event::user::user_t user_from_peripheral(USART_t& usart );
67-
static event::gen::generator_t gen_from_peripheral(TCA_t& timer, uint8_t event_type = 0);
68-
static event::user::user_t user_from_peripheral(TCA_t& timer, uint8_t user_type = 0);
69-
static event::gen::generator_t gen_from_peripheral(CCL_t& logic, uint8_t event_type = 0);
70-
static event::user::user_t user_from_peripheral(CCL_t& logic, uint8_t user_type = 0);
71-
static event::gen::generator_t gen_from_peripheral(AC_t& comp );
64+
static event::gen::generator_t gen_from_peripheral(TCB_t &timer, uint8_t event_type = 0);
65+
static event::user::user_t user_from_peripheral(TCB_t &timer, uint8_t user_type = 0);
66+
static event::user::user_t user_from_peripheral(USART_t &usart);
67+
static event::gen::generator_t gen_from_peripheral(TCA_t &timer, uint8_t event_type = 0);
68+
static event::user::user_t user_from_peripheral(TCA_t &timer, uint8_t user_type = 0);
69+
static event::gen::generator_t gen_from_peripheral(CCL_t &logic, uint8_t event_type = 0);
70+
static event::user::user_t user_from_peripheral(CCL_t &logic, uint8_t user_type = 0);
71+
static event::gen::generator_t gen_from_peripheral(AC_t &comp);
7272

7373
private:
7474
const uint8_t channel_number; // Holds the event generator channel number

0 commit comments

Comments
 (0)