@@ -1041,7 +1041,233 @@ void serialEventRun(void)
1041
1041
//
1042
1042
// Note that THESE values assume F_CPU==32000000
1043
1043
1044
- uint16_t temp_get_baud (unsigned long baud, uint8_t use_u2x)
1044
+ // baud <= F_CPU / 16 for 1x, F_CPU / 8 for 2x - above that gives you a value of '1'
1045
+ //
1046
+ // X = clk_2x ? 8 : 16 bscale >= 0: bsel = F_CPU / ( (2 ^ bscale) * X * baud) - 1
1047
+ // baud = F_CPU / ( (2 ^ bscale) * X * (bsel + 1) )
1048
+ // bscale < 0: bsel = (1 / (2 ^ (bscale))) * (F_CPU / (X * baud) - 1)
1049
+ // baud = F_CPU / ( X * (((2 ^ bscale) * bsel) + 1) )
1050
+ //
1051
+ // NOTE: if bsel is zero for a given bscale, then use bscale=0 and bsel=2^(bscale - 1)
1052
+ // see section 19.3.1
1053
+ //
1054
+ // find 'best fit baud' by calculating the best 'bscale' and 'bsel' for a given baud
1055
+ // bscale is -7 through +7 so this can be done in a simple loop
1056
+ //
1057
+ // Note that I have managed to "nuke out" some accurate integer math to make this work
1058
+ // although the converging solutions tend to take up some time. It's still fast, though
1059
+ // and you won't be calling this very often, now will ya?
1060
+
1061
+ // calculating BSEL and BAUD correctly - this lets me select _ANY_ baud rate
1062
+
1063
+
1064
+ #if 1 // use NEW get_baud - it's about 810 bytes bigger, though
1065
+
1066
+ // GetBSEL returns the BSEL value given the baud and BSCALE
1067
+ // this is more of an estimate. to get the right answer, this is
1068
+ // merely a starting point. you have to converge on the solution
1069
+ // by using a loop and picking the best 'nearby' value, up to '4' away
1070
+ static int GetBSEL (unsigned long lBaud, int nBSCALE, int b2X)
1071
+ {
1072
+ long l1, l3;
1073
+ unsigned char nFactor;
1074
+
1075
+
1076
+ if (b2X)
1077
+ {
1078
+ nFactor = 8 ;
1079
+ }
1080
+ else
1081
+ {
1082
+ nFactor = 16 ;
1083
+ }
1084
+
1085
+ if (nBSCALE >= 0 )
1086
+ {
1087
+ l1 = nFactor * lBaud;
1088
+
1089
+ if (nBSCALE)
1090
+ {
1091
+ l1 = l1 << nBSCALE;
1092
+ }
1093
+
1094
+ if (!l1)
1095
+ {
1096
+ return 0 ;
1097
+ }
1098
+
1099
+ if ((((long )F_CPU) % l1) < (l1 >> 1 ))
1100
+ {
1101
+ l1 = (((long )F_CPU) / l1) - 1 ;
1102
+ }
1103
+ else
1104
+ {
1105
+ l1 = (((long )F_CPU) / l1); // rounded off
1106
+ }
1107
+ }
1108
+ else // nBSCALE < 0
1109
+ {
1110
+ l1 = nFactor * lBaud;
1111
+
1112
+ l3 = F_CPU;
1113
+
1114
+ if (nBSCALE > -4 ) // might overload if I use 32-bit integers and 32Mhz
1115
+ {
1116
+ l3 = l3 << (-nBSCALE);
1117
+ }
1118
+ else
1119
+ {
1120
+ l3 = l3 << 3 ;
1121
+ l1 = l1 >> -(3 + nBSCALE);
1122
+ }
1123
+
1124
+ if (l3 % l1 < (l1 >> 1 ))
1125
+ {
1126
+ l1 = l3 / l1 - 1 ;
1127
+ }
1128
+ else
1129
+ {
1130
+ l1 = l3 / l1; // round up
1131
+ }
1132
+ }
1133
+
1134
+ return (int )l1;
1135
+ }
1136
+
1137
+ // GetBAUD calculates the actual baud rate based on nBSCALE and nBSEL
1138
+ // it is actually pretty accurate, matching what you seen in the manual
1139
+ static long GetBAUD (int nBSCALE, int nBSEL, int b2X)
1140
+ {
1141
+ long l1, l3;
1142
+ unsigned char nFactor;
1143
+ #define GET_BAUD_SCALE_FACTOR 4096 /* scaling the math so I can improve accuracy */
1144
+
1145
+ if (b2X)
1146
+ {
1147
+ nFactor = 8 ;
1148
+ }
1149
+ else
1150
+ {
1151
+ nFactor = 16 ;
1152
+ }
1153
+
1154
+ if (nBSCALE >= 0 )
1155
+ {
1156
+ l1 = (long )nFactor * (nBSEL + 1 ); // nBSEL can be 1-4095; 16 * 4k is ~64k; then it gets shifted.
1157
+
1158
+ if (nBSCALE)
1159
+ {
1160
+ l1 = l1 << nBSCALE;
1161
+ }
1162
+
1163
+ if (!l1)
1164
+ {
1165
+ return 0 ;
1166
+ }
1167
+
1168
+ return ((long )F_CPU) / l1; // TODO: roundoff correction?
1169
+ }
1170
+
1171
+ // nBSCALE < 0
1172
+
1173
+ l3 = (long )nFactor * GET_BAUD_SCALE_FACTOR; // scale factor improves precision
1174
+
1175
+ l1 = l3 * nBSEL;
1176
+
1177
+ if (nBSCALE)
1178
+ {
1179
+ l1 = l1 >> (-nBSCALE);
1180
+ }
1181
+
1182
+ l1 += l3; // the '+ 1' multiplied by nFactor * GET_BAUD_SCALE_SCALE_FACTOR
1183
+
1184
+ if (!l1) // unlikely
1185
+ {
1186
+ return 0 ;
1187
+ }
1188
+
1189
+ l3 = F_CPU % l1; // the remainder - this gives me better rounding with int math
1190
+
1191
+ return GET_BAUD_SCALE_FACTOR * (F_CPU / l1) // integer division, then mult by the scale
1192
+ + (GET_BAUD_SCALE_FACTOR * l3) / l1; // the fractional remainder [scaled]
1193
+ }
1194
+
1195
+ // 'get_baud' - the official baud rate number thingy
1196
+ // this returns (BSCALE << 12) | (BSEL & 0x3fff) for all practical purposes
1197
+ uint16_t get_baud (unsigned long baud, uint8_t use_u2x)
1198
+ {
1199
+ int i1;
1200
+ char i2;
1201
+ char iBSCALE, iBSCALERange;
1202
+ int iBSEL, iTemp;
1203
+ int iMinErr, iErr;
1204
+
1205
+
1206
+
1207
+ // NOTE: 2^ABS(BSCALE) must at most be one half of the minimum number
1208
+ // of clock cycles a frame requires
1209
+
1210
+ iBSCALERange = 7 ; // my initial maximum range
1211
+
1212
+ if (baud > (F_CPU / 1310720 )) // so that the result fits in an integer
1213
+ {
1214
+ iTemp = (int )((F_CPU / 2 ) * 11L / baud); // half the # of clock cycles needed per 11-bits
1215
+
1216
+ while (iBSCALERange && (1 << iBSCALERange) >= iTemp)
1217
+ {
1218
+ iBSCALERange --;
1219
+ }
1220
+ }
1221
+
1222
+ iBSEL = 0 ; // initially zero for 'not found'
1223
+ iBSCALE = 0 ;
1224
+ iMinErr = 0x7fff ; // grossly over expected value of error
1225
+
1226
+ for (i2=-iBSCALERange; i2 <= iBSCALERange; i2++)
1227
+ {
1228
+ iTemp = GetBSEL (baud, i2, use_u2x);
1229
+
1230
+ if (!iTemp || iTemp >= 2048 ) // out of range? - note actual max is 4095
1231
+ {
1232
+ continue ; // don't even look at an invalid value
1233
+ }
1234
+
1235
+ // derived experimentally, loop on range of iTemp - 4 to iTemp + 1
1236
+ for (i1=iTemp > 4 ? iTemp - 4 : 0 ; i1 <= iTemp + 1 ; i1++)
1237
+ {
1238
+ iErr = (int )(GetBAUD (iBSCALE, i1, use_u2x) - baud); // my delta
1239
+
1240
+ if (iErr < 0 ) // smaller than call to 'abs()'
1241
+ {
1242
+ iErr = -iErr;
1243
+ }
1244
+
1245
+ if (iErr < iMinErr)
1246
+ {
1247
+ // I shall keep the first one I find that is below the current min error
1248
+ // and the first 'lowest' error is the one I return. This favors lower
1249
+ // values of BSCALE which I understand helps the baud rate generator
1250
+ // work better overall.
1251
+
1252
+ iBSEL = i1;
1253
+ iBSCALE = i2;
1254
+ iMinErr = iErr; // new error to stay below, now
1255
+ }
1256
+ }
1257
+ }
1258
+
1259
+ if (!iBSEL)
1260
+ {
1261
+ return 1 ; // highest possible baud rate
1262
+ }
1263
+
1264
+ return ((uint16_t )((int )iBSCALE << 12 )) | (uint16_t )(iBSEL & 0x3fff );
1265
+ }
1266
+
1267
+ #else // OLD get_baud
1268
+
1269
+ // the OLD version used baud rate values from a lookup table
1270
+ uint16_t get_baud(unsigned long baud, uint8_t use_u2x)
1045
1271
{
1046
1272
uint16_t i1;
1047
1273
static const unsigned long aBaud[] PROGMEM = // standard baud rates
@@ -1104,25 +1330,10 @@ static const uint16_t a1x[] PROGMEM = // 1x constants for standard baud rates
1104
1330
}
1105
1331
}
1106
1332
1107
- // NOTE: baud <= F_CPU / 16 for 1x, F_CPU / 8 for 2x
1108
- //
1109
- // X = clk_2x ? 8 : 16 bscale >= 0: bsel = F_CPU / ( (2 ^ bscale) * X * baud) - 1
1110
- // baud = F_CPU / ( (2 ^ bscale) * X * (bsel + 1) )
1111
- // bscale < 0: bsel = (1 / (2 ^ (bscale))) * (F_CPU / (X * baud) - 1)
1112
- // baud = F_CPU / ( X * (((2 ^ bscale) * bsel) + 1) )
1113
- //
1114
- // NOTE: if bsel is zero for a given bscale, then use bscale=0 and bsel=2^(bscale - 1)
1115
- // see section 19.3.1
1116
- //
1117
- // find 'best fit baud' by calculating the best 'bscale' and 'bsel' for a given baud
1118
- // bscale is -7 through +7 so this can be done in a simple loop
1119
- // I determined that using floating point is almost MANDATORY to make this work. scaled ints
1120
- // would work too. But it's likely to take up WAY TOO MUCH SPACE in the NVRAM to be practical.
1121
-
1122
1333
return 1; // for now [half the maximum baud rate]
1123
1334
}
1124
1335
1125
-
1336
+ # endif // 0,1
1126
1337
1127
1338
1128
1339
// ///////////////////////////////////////////////////////////////////////////////////////////
@@ -1221,8 +1432,10 @@ void HardwareSerial::begin(unsigned long baud, byte config)
1221
1432
// baud rate calc - page 220 table 19-5 [for standard values]
1222
1433
// table 19-1 (page 211) for calculation formulae
1223
1434
// (also see theory discussion on page 219)
1224
- baud_setting = temp_get_baud (baud, use_u2x);
1435
+ baud_setting = get_baud (baud, use_u2x);
1225
1436
1437
+ // NOTE: I had some difficulty getting 300 baud to work. 600 baud worked ok though
1438
+ // to get 300 baud to work, you might have to change things around a bit
1226
1439
1227
1440
oldSREG = SREG; // save old to restore interrupts as they were
1228
1441
cli (); // clear interrupt flag until I'm done assigning pin stuff
0 commit comments