AnyPWM Revisited

In my original post, I presented an Arduino sketch that could output PWM on any digital pin. It occurred to me spontaneously that the code was horribly inefficient, both in size and execution. So I’ve refactored the code a bit, and now it appears to work at least as well as the built in PWM functions.

The first thing I realized was that the algorithm I was using to track the signals was horribly inefficient; there was way more code and operations than were necessary, and I was tracking too much information. The other thing I realized was that the pulses were not in sync; that might not be too important for most applications, but there might be an application where timing is more critical.

Here’s the code:

1:   // AnyPWM by Nick Borko  
2: // This work is licensed under a Creative Commons
3: // Attribution-ShareAlike 3.0 Unported License
5: // Manually do PWM using FlexiTimer2
6: // (
7: #include
9: // LED to pulse (non-PWM pin)
10: #define LED 13
12: // Period of the PWM wave (and therefore the number of levels)
13: #define PERIOD 256
15: namespace AnyPWM {
16: extern volatile byte pinLevel[12];
17: void pulse();
18: void analogWrite(byte pin, byte level);
19: void init();
20: }
22: // Variables to keep track of the pin states
23: volatile byte AnyPWM::pinLevel[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
25: // Set a digital out pin to a specific level
26: void AnyPWM::analogWrite(byte pin, byte level) {
27: if (pin > 1 && pin < 14 && level >= 0 && level < PERIOD) {
28: pin -= 2;
29: AnyPWM::pinLevel[pin] = level;
30: if (level == 0) {
31: digitalWrite(pin + 2, LOW);
32: }
33: }
34: }
36: // Initialize the timer routine; must be called before calling
37: // AnyPWM::analogWrite!
38: void AnyPWM::init() {
39: // (PERIOD * 64) Hertz seems to be a high enough frequency to produce
40: // a steady PWM signal on all 12 output pins
41: FlexiTimer2::set(1, 1.0/(PERIOD * 64), AnyPWM::pulse);
42: FlexiTimer2::start();
43: }
45: // Routine to emit the PWM on the pins
46: void AnyPWM::pulse() {
47: static int counter = 0;
48: for(int i = 0; i < 12; i += 1) {
49: if (AnyPWM::pinLevel[i]) {
50: digitalWrite(i + 2, AnyPWM::pinLevel[i] > counter);
51: }
52: }
53: counter = ++counter > PERIOD ? 0 : counter;
54: }
56: void setup() {
57: AnyPWM::init(); // initialize the PWM timer
58: pinMode(LED, OUTPUT); // declare LED pin to be an output
59: }
61: byte brightness = 0; // how bright the LED is
62: byte fadeAmount = 5; // how many points to fade the LED by
64: void loop() {
65: // set the brightness of the LED:
66: AnyPWM::analogWrite(LED, brightness);
68: // change the brightness for next time through the loop:
69: brightness = brightness + fadeAmount;
71: // reverse the direction of the fading at the ends of the fade:
72: if (brightness == 0 || brightness == 255) {
73: fadeAmount = -fadeAmount;
74: }
75: // wait for 30 milliseconds to see the dimming effect
76: delay(30);
77: }

Download code

The first thing to notice is that I’ve gotten rid of 2 arrays: state and timer. These are completely unnecessary, and it saves 24 bytes right off the top. Second, I’ve upped my multiplier to calculate the timer frequency to 64, which makes for smoother levels when more pins are being pulsed. Finally, a lot of code in the pulse() function has been replaced with a simple comparison against a single rolling counter, making the CPU time spent in the routine much shorter.

The entire code savings is about 80 bytes from the original, which makes this sketch come in at 2114 bytes, compared to the 1252 bytes of the compiled Fade sketch (862 byte difference). Additionally, the performance is much closer to the built in analogWrite() functionality. I don’t know the exact timing, but the difference is fairly imperceptible to a human, even when pulsing 6 pins (the maximum number of PWM pins on an ATmegaXX8 Arduino).

PWM on Any Digital Pin on Arduino

I recently got an Arduino to play around with. It’s been a few years since I’ve done some electronics hacking, and I wanted to get back into the hobby. There are tons of low cost embedded microcontrollers to play with these days, compared to when I was back in college, so I decided to give the Arduino a try. My first experiment was to emit PWM signals on any of the digital output pins.

My real goal was to learn how to use the hardware interrupt timers in general in the Arduino environment. I knew I would have to do this to implement my impending hardware project to build a 16×8 LED matrix light board. Fortunately doing that is pretty much like any microcontroller, so it’s not too difficult to figure out from the documentation. Even more fortunately, Wim Leers abstracted out all the necessary logic to figure out the current clock speed and timer implementations of various Arduino platforms, making it child’s play to set up an interrupt timer routine. His library co-opts timer 2 and is called FlexiTimer2.

Pulse-Width Modulation is simply manipulating the high and low value durations of a fixed period digital waveform to simulate an analog signal level. Well, maybe it’s not that simple, but you can check out the Wikipedia page to get a more technically correct explanation. In any case, the Arduino bootstrap environment provides PWM output on specific pins through a call to analogWrite. While some ATmega pins support hardware PWM, on others it is done in software using timers. My sketch does this as well:

1:   // AnyPWM by Nick Borko  
2: // This work is licensed under a Creative Commons
3: // Attribution-ShareAlike 3.0 Unported License
5: // Manually do PWM using FlexiTimer2
6: // (
7: #include
9: // LED to pulse (non-PWM pin)
10: #define LED 13
12: // Period of the PWM wave (and therefore the number of levels)
13: #define PERIOD 256
15: namespace AnyPWM {
16: extern volatile byte pinLevel[12];
17: extern boolean state[12];
18: extern byte timer[12];
19: void pulse();
20: void analogWrite(byte pin, byte level);
21: void init();
22: }
24: // Variables to keep track of the pin states
25: volatile byte AnyPWM::pinLevel[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
26: boolean AnyPWM::state[12] = { LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW };
27: byte AnyPWM::timer[12] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
29: // Set a digital out pin to a specific level
30: void AnyPWM::analogWrite(byte pin, byte level) {
31: if (pin > 1 && pin < 14 && level >= 0 && level < PERIOD) {
32: pin -= 2;
33: AnyPWM::pinLevel[pin] = level;
34: if (level == 0) {
35: // reset the PWM state
36: AnyPWM::state[pin] = LOW;
37: AnyPWM::timer[pin] = 255;
38: digitalWrite(pin + 2, LOW);
39: }
40: }
41: }
43: // Initialize the timer routine; must be called before calling
44: // AnyPWM::analogWrite!
45: void AnyPWM::init() {
46: // (PERIOD * 48) Hertz seems to be a high enough frequency to produce
47: // a steady PWM signal on all 12 output pins
48: FlexiTimer2::set(1, 1.0/(PERIOD * 48), AnyPWM::pulse);
49: FlexiTimer2::start();
50: }
52: // Routine to emit the PWM on the pins
53: void AnyPWM::pulse() {
54: for(int i = 0; i < 12; i += 1) {
55: if (AnyPWM::pinLevel[i]) {
56: if (AnyPWM::timer[i] == 0) {
57: AnyPWM::timer[i] = (AnyPWM::state[i] = !AnyPWM::state[i]) ? AnyPWM::pinLevel[i] : (byte)PERIOD - AnyPWM::pinLevel[i];
58: } else {
59: digitalWrite(i + 2, AnyPWM::state[i]);
60: }
61: AnyPWM::timer[i] -= 1;
62: }
63: }
64: }
66: void setup() {
67: AnyPWM::init(); // initialize the PWM timer
68: pinMode(LED, OUTPUT); // declare LED pin to be an output
69: }
71: byte brightness = 0; // how bright the LED is
72: byte fadeAmount = 5; // how many points to fade the LED by
74: void loop() {
75: // set the brightness of the LED:
76: AnyPWM::analogWrite(LED, brightness);
78: // change the brightness for next time through the loop:
79: brightness = brightness + fadeAmount;
81: // reverse the direction of the fading at the ends of the fade:
82: if (brightness == 0 || brightness == 255) {
83: fadeAmount = -fadeAmount;
84: }
85: // wait for 30 milliseconds to see the dimming effect
86: delay(30);
87: }

Download code

Now, a LED attached to pin 13 (or the surface mounted LED on some Arduino boards), a non-PWM pin, will pulse, just like the Fade sketch in the Examples (you’ll note the loop code is nearly identical).

There are some downsides to this approach. First, the code is 942 bytes longer than using the stock analogWrite call on a PWM pin. Second, since all pins share the same timer, the more pins you write to, the slower the execution. This may be an acceptable trade off, and the timing issue may be mitigated by decreasing the duty cycle (PERIOD) while keeping the timer frequency the same (set in AnyPWM:init via FlexiTimer2::set).

This same approach could be used for other applications than PWM. For example, you could control an RGB LED matrix to provide up to 24-bit color, assuming the processor was fast enough; instead of controlling multiple output pins, you could instead be controlling the individual red, green and blue values for each LED through a serial driver. Or, 16 levels of brightness on a single color LED array (if PERIOD is set to 16), which I am thinking about doing for my LED project.

UPDATE: Don’t use this code! Instead, read my follow-up and download the code!

Sub’r Bowl Review: Subway

The Sub’r Bowl contender this week is the most well known but least anticipated Subway, the king of Division A and, well, just about every sandwich shop in existence. With more than 33,000 stores, that’s now more locations than McDonalds!

Since I had discovered that Subway was offering a “$5 Any Footlong” deal for the month of February, I made the call for this to be the next place to hit. My thinking was, if I have to eat a Subway sandwich, why should I pay full price? The location near our workplace is full of employees with bad attitudes and sandwich making skills to match, so we opted to travel the extra mile or so to the next nearest location. Did I mention they have over 33,000 locations?

Subway does a lot of business, especially around lunch time. Even though we went at 1pm, hoping to be past the lunch rush, the parking lot was nearly full, and, since this location had a drive through, cars were stacked out past the entrance waiting to order. Despite that, we were able to order right away inside the restaurant, and the staff was friendly and fast.

Greg and I both opted for the BMT Italian sub, probably the best known Subway sandwich, with lettuce, tomatoes, olives, mayo, Italian dressing and salt and pepper. He ordered his cold and I toasted, and we each took half the other’s sandwich. A small difference was that I ordered banana peppers on half of mine, which I split between my 2 halves. Dave was present and ordered his usual Sweet Onion Chicken Teriyaki, and Kelley ordered a meatball sub.

Subway offers 5 different kinds of bread, but I went with the classic Italian bread. For the cold sandwich the bread was soft and slightly chewy, and it held up pretty well. The toasted sub was pretty much the same, but there was a small added crunch that I preferred. Inside, both sandwiches tasted pretty much the same, whether toasted or not. The meats were of average quality but had a good flavor, and with the dressing and peppers the sandwiches had a lot of bite.

One problem I had with the sandwich was that it was too “drippy.” This was especially true of Greg’s cold sandwich, of which there was too much dressing and mayo for my taste. I had asked for only a small amount of light mayo for mine, and I noticed that she also put on less dressing. The effect was that my sandwich had a lot bolder flavor of the meats, which made my mouth water a lot, whereas the cold sandwich, with 3 times the amount of mayo, was more muted in flavor.

For $6 we got a Footlong and any size drink. Fortunately (especially for Greg) they offer Coca-Cola products, and I got plenty of Coke Zero. It was a good amount of food, and I was definitely full after eating the sandwich. You can get chips (mostly Frito-Lay snack size chips) as well as other “healthy” sides, but I didn’t feel like I needed any.

I rated the following categories:

  • Bread: 3
  • Sandwich Stuff: 3
  • Price/Value: 7
  • Non-sandwich Stuff: 3
  • Bonus points: 0
  • Total: 16 points

I knew what to expect at Subway, as I’ve been there many times over the years. They serve a decent sandwich at a decent price. This time out, it was a fantastic deal for $6 for a Footlong and a drink, which would normally be closer to $7.50 without the special. It’s certainly the cheapest I expect to pay in this challenge, and they’re getting the highest points in price and value. It was an average but solid sandwich that left me satisfied and full.

See also:
Greg’s Review

Sub’r Bowl Review: Ray’s Pizzaria

This week’s challenger is an alternate that’s stepped up to be first in the Pizza Shop division: Ray’s Pizzaria (sic, herein referred to as simply “Ray’s,” because the misspelling of pizzeria makes my spell checker and baby Jesus cry). Ray’s is previously the Blanco location of Goomba’s Pizzeria (correctly spelled) but is supposedly run by the same people. I don’t really know what that means, since there is a specific owner of Goomba’s, but this is a review of a sandwich, not restaurant history.

Ray’s replaces Rome’s Pizza (web site returns an error at last check), which is now closed, on the original schedule. I understand there may still be locations operating in the city, and if that’s true then it can hold a place on the alternates list. I’m not sure why Ray’s née Goomba’s wasn’t originally on the schedule, but everyone agreed that it was a good substitution.

Normally I’d order a couple slices or split a pie for lunch, but today was about the subs. They only had an Italian and club on the cold sub menu, with hot sandwiches including the “Sicilian” (more on that in a moment); a meatball, chicken or eggplant parm sub; and a cheese steak sandwich. I wouldn’t have minded one of the hot sandwiches, but to me a sub is cold cuts. Since the Sicilian was described as having “Italian meats” with lettuce, tomatoes and olives, it sort of sounded like it could be something other than what it turned out to be: a hot Italian sub. So, I instead opted for a “half” Italian sub, a slice of cheese pizza, fries and a drink. Let me explain how this combination came about:

The sandwiches are sold in “half” and “full” sizes, with half being $4.95 and the full $7.95. A slice is $1.95. Some quick mental math tells me that a half sub plus a slice is cheaper and probably more food. Some quick non-mental non-math tells me that I need a slice of pizza. The fries enter the equation because when I ordered a drink, $1.75, I was asked if I wanted the fries and drink combo for $2. So for $0.25, I can try the fries as a side for my sandwich. Spoiler: What a waste of 25 perfectly good cents.

Surprisingly, the slice came out first. In hindsight I probably should have put the hot oil and cheesy goodness into my mouth after trying the sub; but I was hungry, and the slice was perfectly made. As Greg pointed out, maybe that contributed to the overall letdown of the sub itself. The bread was a standard Italian roll, toasted, but otherwise unremarkable. It was apparently covered with a brushing of melted butter, parm cheese and either parsley or oregano. I wouldn’t know which, because most of it ended up on my hand and not in my mouth. That made the sandwich much more messy than it should have been and didn’t really add anything to the overall flavor.

The insides consisted of salami, capicola, ham and provolone. As for the vegetables, there were small but adequate pieces romaine lettuce and one very thin tomato slice cut in half. There was a decent amount of the meats, but if you hadn’t told me what they were, I might have said it was just a cold-cut sandwich. And when I think about it, save for the capicola, that’s what it was, and the “capicola” couldn’t have truly been such. If you had told me it was Canadian bacon, I would have told you, “no way, Canadian bacon has more flavor than this.”

After about 2 bites of the sandwich and discovering my disappointment at the blandness of it, I realized one of the major flaws: there was no dressing. I was eating a dry cold-cut sandwich on a hard roll! I went to the serving counter and asked for some Italian dressing, which they readily gave me. What a difference that made to the taste of the sandwich, but only from “disappointing” to “adequate.” Another major flaw was that it had no peppers, olives or any other kind of garnish or seasoning that would have made it anything other than what it was: a cold-cut sandwich.

Greg and Dave each ordered the “Sicilian” hot sandwich, but since it was served without the advertised olives, it just turned out to be exactly the same as my sandwich, but hot. (Update: Dave reports there are some chopped olives on his leftover sandwich). As served, the sandwich was worse than the one I got at R&B;’s; if you put the two sandwiches in front of me, based on taste alone, I would have to pick R&B;’s. The only equalizer is that Ray’s sub is $2 cheaper and will make you feel more full, if price is a factor. The fries were just as previously frozen and overcooked as R&B;’s, and, though they only cost me $0.25 extra, I wouldn’t bother next time.

I rated the following categories:

  • Bread: 3
  • Sandwich Stuff: 3
  • Price/Value: 6
  • Non-sandwich Stuff: 0
  • Bonus points: 2
  • Total: 14 points

The sandwich at Ray’s was disappointing to me in a similar way that the sandwich at R&B;’s was: I really liked the food I had had there before, and I was hoping for better than what I was served. The only bright spot of this visit was the excellent slice of cheese pizza, which was enough to make the experience better than R&B;’s, so I gave Ray’s 2 bonus points. However, it’s going to take a pretty dismal showing of all the other restaurants in this division if Ray’s is going to make an appearance in the semifinals.

See Also:
Greg’s Review

Sub’r Bowl Review: Earl of Sandwich

My second review for the SUB’r Bowl is the Earl of Sandwich. It’s in the National Chain Restaurant, Under 1000 Locations division.

Last I checked Earl of Sandwich had locations in Nevada, Michigan, Florida, Pennsylvania, Massachusetts, and, of course, Texas. Oh, and there’s apparently one scheduled to open in Disney Village in Paris, France. This probably has something to do with the fact that the first shop opened in the Disney Resort in Orlando, FL. Whatever the rhyme or reason for the franchising locations, I’m glad there is not one but THREE locations in San Antonio alone; and, as far as I can tell, that’s the highest concentration anywhere.

Although you can get soup and salad, the primary product of Earl of Sandwich is their hot subs. They’re all made on an “artisan baked loaf,” which is baked in the store. The bread is the perfect sandwich bread: lightly crusty on the outside, soft and slightly chewy in the inside, with a hint of buttery goodness. It did have one weakness though, which I’ll describe later.

They have over 12 sandwiches on the menu, so we asked what their most popular sandwich was. The guy at the counter told us both the Earl’s Club, which more or less sports classic club sandwich innards, and the Full Montagu (named for the Earl of Sandwich), containing roast beef, turkey, swiss and cheddar cheeses, lettuce, tomatoes and “the Earl’s Mustard Sauce,” were their best sellers. Greg and I were both mulling over the Full Montagu as well as the Italian, our de facto standard for comparison, so we decided that we’d each order one or the other, then split them so we could each try both sandwiches.

For me, first up was the Full Montagu. The meat was shaved thin, so it was kind of piled on the bread, topped with the cheese, lettuce and roma tomato slices. The mustard sauce tasted to me more or less like a salty dijon mustard with a bit of honey (or perhaps high fructose corn syrup; I don’t know exactly what the ingredients are). It was a good flavor combination, but it didn’t “wow” me. That is, until I got to the end of the sandwich, where the roma tomato had been placed.

Apparently the sandwich had only 2 slices of tomato on each half of the sandwich, positioned toward the ends of the bread. That seems kind of frugal to me, but maybe it makes more sense if I was eating the entire sandwich. However, since the sandwich is cut in half, you tend to eat from the middle to the ends. I wish I had moved the tomato toward the middle of the sandwich, because that changed the whole flavor profile of the sandwich to something closer to “wow.”

Next up was the Italian, and the flavor of this one did wow me from the start. This was an excellent tasting sandwich, but it had a couple of flaws. The first one was the somewhat soggy bread from the Italian dressing. This probably wouldn’t have been so much of a problem had I tackled this sandwich first. As I mentioned earlier, the bread is great, but for an Italian sub I would have liked a more robust bread that could have stood up to the vinegar and oil a little better.

Secondly, I was missing the taste of peppers on the sandwich, hot or sweet. I found out later, after picking up a to-go menu, that I had the option of having peppers on the sandwich; however, I was not informed of the option or asked by the employee taking my order if I wanted peppers on the sandwich. I see this more as a service failure than a sandwich failure though, but I’ll never know how much better (or perhaps worse) the sandwich could have been.

I ordered the combo, which comes with chips and a drink. I got the Earl of Sandwich labeled salt and vinegar kettle chips, which were only lightly tangy. I wouldn’t choose these chips as a standalone snack, but, as an accompaniment, it had just the right amount of bite without overpowering the sandwich. The soft drinks, Pepsi products, were all flat; I informed an employee, and I saw about 5 minutes later someone came out to swap out the CO2. I’m not into Pepsi products anyway, so it wasn’t that big of a deal for me. Instead I got some of the “Earl’s Grey Lemonade.” It’s billed as mix of lemonade and Earl Grey tea, but it was a fusion that didn’t work for me. It was pretty strong on the sour lemon side, but not sweet enough, and the tea just kind of clashed with the flavor of the thing. It might have been better if I had sweetened it more, but I didn’t feel like it was worth refilling to try.

I rated the following categories:

  • Bread: 6
  • Sandwich Stuff: 6
  • Price/Value: 6
  • Non-sandwich Stuff: 3
  • Bonus points: 0
  • Total: 21 points

I enjoy going to the Earl of Sandwich. I’ve been there many times in the past, and my favorite sandwich is the All American, which tastes like Thanksgiving in a sandwich. So I was not surprised at all by the high ratings these sandwiches received and the compliments from all who went. Even though it’s a national franchise, it has the prices of a local sub shop ($5.95 for an approximately 9 inch sandwich), but it’s totally worth it. Highly recommended for anyone who likes a gourmet sub.

See Also:
Greg’s Review

Sub’r Bowl Review: R&B’s Taste of Chicago

This is my first review for our little “SUB’r Bowl” we’re playing at work. Each week we try a different sub shop from one of 16 sub places, broken up into 4 “divisions” and 2 “conferences.” The first place we tried was R&B;’s Taste of Chicago.

Since this is the first place I’m reviewing, I’m going to briefly outline how we’ve broken up the 16 restaurants:

Conference 1:
National Chain Restaurants
Conference 2:
Local Restaurants
Division A:
Over 1000 Locations
Division B:
Under 1000 Locations
Division C:
Sandwich Shops
Division D:
Pizza Shops
• Blimpie
• Jimmy Johns
• Quiznos
• Subway
• Earl of Sandwich
• Firehouse Subs
• Jasons Deli
• Lenny’s Sub Shop
• Boston Subworks
• R&B;’s Taste of Chicago
• Thundercloud Subs
• W D Deli
• Florio’s
• Main Street Pizza
Romes Pizza Ray’s Pizzaria
VJ’s Pizza Cerroni’s the Original Purple Garlic

The divisions are totally arbitrary, and the schedule is whatever we feel like. The participants are myself, Dave, Greg and Kelley. Rating categories score one of 0/3/6/7, based on football scoring (field goal, TD, TD + extra point). There is also a “bonus” category, in which 2 points can be awarded at discretion, if there was something extra outstanding about the experience.

Now that that’s out of the way, on to the review!

As I mentioned, our first contender was R&B;’s Taste of Chicago. R&B;’s has a reputation for serving real Chicago-style food using Vienna beef products.  I first found this place a couple years ago when I drove by the strip plaza on Austin Highway and stopped in to see what it was. I’ve been there a couple of times, and both times I had the hot Italian Beef sub, R&B;’s being the only place in town I know of that serves it.

For the purposes of this visit, I ordered the Zesty Italian sub. They apparently have 3 versions of the Italian sub, each with a successive addition of meat: the Classic, the Zesty and the Supreme. They were apparently out of prosciutto, which makes the Supreme “better” than the Zesty, or I would have probably ordered the Supreme. There was a choice of hot or sweet peppers, and I picked the hot (crushed cherry) peppers.

It took about 10 minutes to fill the order, which seemed kind of long for a relatively simple sandwich and not a large crowd.  The sandwich was about 7 inches long on an Italian bread roll.  It was toasted, but too much in my opinion, when the bread is scraping against the top of your mouth.  There was nothing wrong really with the bread, but there was nothing special about it either.

The insides of the sandwich were fairly underwhelming: 1 slice each of provolone, ham, capicola ham, and genoa salami, lettuce, tomato, spices and peppers.  There was supposed to be pickles on it as well, but I didn’t notice any.  It was odd to me that the meat was laying on top of everything else, but maybe it was to make it look like there was more meat than there actually was.  It was a decent tasting sandwich, and the meats were good quality, but overall the sandwich just seemed average. It didn’t taste anything better than what I could make myself with a hard roll and cold cuts, and, despite the quality of the meats, not really worth $6+.

The drink selection was kind of disappointing: Pepsi products and some really weak iced tea. I opted for the tea, since Pepsi products don’t really float my boat, so they really made a killing on my drink. And it was wholly unsatisfying, save for that it was wet.

I tried some of the sides the other guys ordered.  The french fries were of the Sam’s Club variety and overly fried. Ditto for the onion rings, which were breaded but otherwise had no detectable spices.  There was something “off” about the taste of the fried foods, and I decided that perhaps the oil was just too old.

I rated the following categories:

  • Bread: 3
  • Sandwich Stuff: 6
  • Price/Value: 3
  • Non-sandwich Stuff: 0
  • Bonus points: 0
  • Total: 12 points

I rather enjoy the hot Italian beef sandwich when I get it from R&B;, so I really wanted to like the sub. However, it was just so unremarkable all around that I can’t give it any higher marks.  The actual meat, what little of it was there, was really good quality and very tasty, so I felt I could give it high marks for that; but there just wasn’t enough of it to make it a truly outstanding sandwich.

See Also:
Greg’s Review