You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

496 lines
14KB

  1. // Copyright 2009 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // -----------------------------------------------------------------------------
  17. //
  18. // An alternative gpio library based on templates.
  19. //
  20. // Examples of use:
  21. //
  22. // NumberedGpio<3>::set_mode(DIGITAL_INPUT)
  23. // NumberedGpio<4>::set_mode(DIGITAL_OUTPUT)
  24. // NumberedGpio<3>::value()
  25. // NumberedGpio<4>::High()
  26. // NumberedGpio<4>::Low()
  27. // NumberedGpio<4>::set_value(1)
  28. // NumberedGpio<4>::set_value(0)
  29. #ifndef AVRLIB_GPIO_H_
  30. #define AVRLIB_GPIO_H_
  31. #include <avr/io.h>
  32. #include "avrlib/avrlib.h"
  33. #include "avrlib/timer.h"
  34. namespace avrlib {
  35. enum PinMode {
  36. DIGITAL_INPUT = 0,
  37. DIGITAL_OUTPUT = 1,
  38. PWM_OUTPUT = 2
  39. };
  40. // All the registers used in the following definitions are wrapped here.
  41. IORegister(DDRB);
  42. IORegister(DDRC);
  43. IORegister(DDRD);
  44. IORegister(PORTB);
  45. IORegister(PORTC);
  46. IORegister(PORTD);
  47. IORegister(PINB);
  48. IORegister(PINC);
  49. IORegister(PIND);
  50. // Represents a i/o port, which has input, output and mode registers.
  51. template<typename InputRegister, typename OutputRegister,
  52. typename ModeRegister>
  53. struct Port {
  54. typedef InputRegister Input;
  55. typedef OutputRegister Output;
  56. typedef ModeRegister Mode;
  57. };
  58. // Definition of I/O ports.
  59. typedef Port<PINBRegister, PORTBRegister, DDRBRegister> PortB;
  60. typedef Port<PINCRegister, PORTCRegister, DDRCRegister> PortC;
  61. typedef Port<PINDRegister, PORTDRegister, DDRDRegister> PortD;
  62. #if defined(ATMEGA164P) || defined(ATMEGA324P) || defined(ATMEGA644P) || defined(ATMEGA1284P) || defined(ATMEGA2560)
  63. IORegister(DDRA);
  64. IORegister(PORTA);
  65. IORegister(PINA);
  66. typedef Port<PINARegister, PORTARegister, DDRARegister> PortA;
  67. #endif
  68. #if defined (ATMEGA640) || defined (ATMEGA1280) || defined(ATMEGA2560)
  69. IORegister(DDRE);
  70. IORegister(DDRF);
  71. IORegister(DDRG);
  72. IORegister(DDRH);
  73. IORegister(DDRJ);
  74. IORegister(DDRK);
  75. IORegister(DDRL);
  76. IORegister(PORTE);
  77. IORegister(PORTF);
  78. IORegister(PORTG);
  79. IORegister(PORTH);
  80. IORegister(PORTJ);
  81. IORegister(PORTK);
  82. IORegister(PORTL);
  83. IORegister(PINE);
  84. IORegister(PINF);
  85. IORegister(PING);
  86. IORegister(PINH);
  87. IORegister(PINJ);
  88. IORegister(PINK);
  89. IORegister(PINL);
  90. typedef Port<PINERegister, PORTERegister, DDRERegister> PortE;
  91. typedef Port<PINFRegister, PORTFRegister, DDRFRegister> PortF;
  92. typedef Port<PINGRegister, PORTGRegister, DDRGRegister> PortG;
  93. typedef Port<PINHRegister, PORTHRegister, DDRHRegister> PortH;
  94. typedef Port<PINJRegister, PORTJRegister, DDRJRegister> PortJ;
  95. typedef Port<PINKRegister, PORTKRegister, DDRKRegister> PortK;
  96. typedef Port<PINLRegister, PORTLRegister, DDRLRegister> PortL;
  97. #endif
  98. // The actual implementation of a pin, not very convenient to use because it
  99. // requires the actual parameters of the pin to be passed as template
  100. // arguments.
  101. template<typename Port, typename PwmChannel, uint8_t bit>
  102. struct GpioImpl {
  103. typedef BitInRegister<typename Port::Mode, bit> ModeBit;
  104. typedef BitInRegister<typename Port::Output, bit> OutputBit;
  105. typedef BitInRegister<typename Port::Input, bit> InputBit;
  106. typedef PwmChannel Pwm;
  107. static inline void set_mode(uint8_t mode) {
  108. if (mode == DIGITAL_INPUT) {
  109. ModeBit::clear();
  110. } else if (mode == DIGITAL_OUTPUT || mode == PWM_OUTPUT) {
  111. ModeBit::set();
  112. }
  113. if (mode == PWM_OUTPUT) {
  114. PwmChannel::Start();
  115. } else {
  116. PwmChannel::Stop();
  117. }
  118. }
  119. static inline void High() {
  120. OutputBit::set();
  121. }
  122. static inline void Low() {
  123. OutputBit::clear();
  124. }
  125. static inline void Toggle() {
  126. OutputBit::toggle();
  127. }
  128. static inline void set_value(uint8_t value) {
  129. if (value == 0) {
  130. Low();
  131. } else {
  132. High();
  133. }
  134. }
  135. static inline void set_pwm_value(uint8_t value) {
  136. if (PwmChannel::has_pwm) {
  137. PwmChannel::Write(value);
  138. } else {
  139. set_value(value);
  140. }
  141. }
  142. static inline uint8_t value() {
  143. return InputBit::value();
  144. }
  145. static inline uint8_t is_high() {
  146. return InputBit::value();
  147. }
  148. static inline uint8_t is_low() {
  149. return InputBit::value() == 0;
  150. }
  151. };
  152. template<typename port, uint8_t bit>
  153. struct Gpio {
  154. typedef GpioImpl<port, NoPwmChannel, bit> Impl;
  155. static void High() { Impl::High(); }
  156. static void Low() { Impl::Low(); }
  157. static void Toggle() { Impl::Toggle(); }
  158. static void set_mode(uint8_t mode) { Impl::set_mode(mode); }
  159. static void set_value(uint8_t value) { Impl::set_value(value); }
  160. static void set_pwm_value(uint8_t value) { Impl::set_pwm_value(value); }
  161. static uint8_t value() { return Impl::value(); }
  162. static uint8_t is_low() { return Impl::is_low(); }
  163. static uint8_t is_high() { return Impl::is_high(); }
  164. };
  165. struct DummyGpio {
  166. static void High() { }
  167. static void Low() { }
  168. static void set_mode(uint8_t mode) { }
  169. static void set_value(uint8_t value) { }
  170. static void set_pwm_value(uint8_t value) { }
  171. static uint8_t value() { return 0; }
  172. static uint8_t is_low() { return 0; }
  173. static uint8_t is_high() { return 0; }
  174. };
  175. template<typename Gpio>
  176. struct Inverter {
  177. static void High() { Gpio::Low(); }
  178. static void Low() { Gpio::High(); }
  179. static void set_mode(uint8_t mode) { Gpio::set_mode(mode); }
  180. static void set_value(uint8_t value) { Gpio::set_value(!value); }
  181. static void set_pwm_value(uint8_t value) { Gpio::set_pwm_value(~value); }
  182. static uint8_t value() { return !Gpio::value(); }
  183. static uint8_t is_low() { return !Gpio::is_low(); }
  184. static uint8_t is_high() { return !Gpio::is_high(); }
  185. };
  186. template<typename gpio>
  187. struct DigitalInput {
  188. enum {
  189. buffer_size = 0,
  190. data_size = 1,
  191. };
  192. static void Init() {
  193. gpio::set_mode(DIGITAL_INPUT);
  194. }
  195. static void EnablePullUpResistor() {
  196. gpio::High();
  197. }
  198. static void DisablePullUpResistor() {
  199. gpio::Low();
  200. }
  201. static uint8_t Read() {
  202. return gpio::value();
  203. }
  204. };
  205. // A template that will be specialized for each pin, allowing the pin number to
  206. // be specified as a template parameter.
  207. template<int n>
  208. struct NumberedGpioInternal { };
  209. // Macro to make the pin definitions (template specializations) easier to read.
  210. #define SetupGpio(n, port, timer, bit) \
  211. template<> struct NumberedGpioInternal<n> { \
  212. typedef GpioImpl<port, timer, bit> Impl; };
  213. // Pin definitions for ATmega lineup
  214. #if defined(ATMEGA48P) || defined(ATMEGA88P) || defined(ATMEGA168P) || defined(ATMEGA328P)
  215. SetupGpio(0, PortD, NoPwmChannel, 0);
  216. SetupGpio(1, PortD, NoPwmChannel, 1);
  217. SetupGpio(2, PortD, NoPwmChannel, 2);
  218. SetupGpio(3, PortD, PwmChannel2B, 3);
  219. SetupGpio(4, PortD, NoPwmChannel, 4);
  220. SetupGpio(5, PortD, PwmChannel0B, 5);
  221. SetupGpio(6, PortD, PwmChannel0A, 6);
  222. SetupGpio(7, PortD, NoPwmChannel, 7);
  223. SetupGpio(8, PortB, NoPwmChannel, 0);
  224. SetupGpio(9, PortB, PwmChannel1A, 1);
  225. SetupGpio(10, PortB, PwmChannel1B, 2);
  226. SetupGpio(11, PortB, PwmChannel2A, 3);
  227. SetupGpio(12, PortB, NoPwmChannel, 4);
  228. SetupGpio(13, PortB, NoPwmChannel, 5);
  229. SetupGpio(14, PortC, NoPwmChannel, 0);
  230. SetupGpio(15, PortC, NoPwmChannel, 1);
  231. SetupGpio(16, PortC, NoPwmChannel, 2);
  232. SetupGpio(17, PortC, NoPwmChannel, 3);
  233. SetupGpio(18, PortC, NoPwmChannel, 4);
  234. SetupGpio(19, PortC, NoPwmChannel, 5);
  235. SetupGpio(255, PortB, NoPwmChannel, 0);
  236. typedef Gpio<PortB, 5> SpiSCK;
  237. typedef Gpio<PortB, 4> SpiMISO;
  238. typedef Gpio<PortB, 3> SpiMOSI;
  239. typedef Gpio<PortB, 2> SpiSS;
  240. typedef Gpio<PortD, 4> UartSpi0XCK;
  241. typedef Gpio<PortD, 1> UartSpi0TX;
  242. typedef Gpio<PortD, 0> UartSpi0RX;
  243. #define HAS_USART0
  244. #elif defined(ATMEGA164P) || defined(ATMEGA324P) || defined(ATMEGA644P) || defined(ATMEGA1284P)
  245. SetupGpio(0, PortB, NoPwmChannel, 0);
  246. SetupGpio(1, PortB, NoPwmChannel, 1);
  247. SetupGpio(2, PortB, NoPwmChannel, 2);
  248. SetupGpio(3, PortB, PwmChannel0A, 3);
  249. SetupGpio(4, PortB, PwmChannel0B, 4);
  250. SetupGpio(5, PortB, NoPwmChannel, 5);
  251. SetupGpio(6, PortB, NoPwmChannel, 6);
  252. SetupGpio(7, PortB, NoPwmChannel, 7);
  253. SetupGpio(8, PortD, NoPwmChannel, 0);
  254. SetupGpio(9, PortD, NoPwmChannel, 1);
  255. SetupGpio(10, PortD, NoPwmChannel, 2);
  256. SetupGpio(11, PortD, NoPwmChannel, 3);
  257. SetupGpio(12, PortD, PwmChannel1B, 4);
  258. SetupGpio(13, PortD, PwmChannel1A, 5);
  259. SetupGpio(14, PortD, PwmChannel2B, 6);
  260. SetupGpio(15, PortD, PwmChannel2A, 7);
  261. SetupGpio(16, PortC, NoPwmChannel, 0);
  262. SetupGpio(17, PortC, NoPwmChannel, 1);
  263. SetupGpio(18, PortC, NoPwmChannel, 2);
  264. SetupGpio(19, PortC, NoPwmChannel, 3);
  265. SetupGpio(20, PortC, NoPwmChannel, 4);
  266. SetupGpio(21, PortC, NoPwmChannel, 5);
  267. SetupGpio(22, PortC, NoPwmChannel, 6);
  268. SetupGpio(23, PortC, NoPwmChannel, 7);
  269. SetupGpio(255, PortB, NoPwmChannel, 0);
  270. typedef Gpio<PortB, 7> SpiSCK;
  271. typedef Gpio<PortB, 6> SpiMISO;
  272. typedef Gpio<PortB, 5> SpiMOSI;
  273. typedef Gpio<PortB, 4> SpiSS;
  274. typedef Gpio<PortB, 0> UartSpi0XCK;
  275. typedef Gpio<PortD, 1> UartSpi0TX;
  276. typedef Gpio<PortD, 0> UartSpi0RX;
  277. typedef Gpio<PortD, 4> UartSpi1XCK;
  278. typedef Gpio<PortD, 3> UartSpi1TX;
  279. typedef Gpio<PortD, 2> UartSpi1RX;
  280. #define HAS_USART0
  281. #define HAS_USART1
  282. #if defined(ATMEGA1284P) || defined(ATMEGA640) || defined(ATMEGA1280) \
  283. || defined(ATMEGA2560)
  284. #define HAS_TIMER3
  285. #endif
  286. #elif defined (ATMEGA640) || defined(ATMEGA1280) || defined(ATMEGA2560)
  287. SetupGpio(0, PortB, NoPwmChannel, 0);
  288. SetupGpio(1, PortB, NoPwmChannel, 1);
  289. SetupGpio(2, PortB, NoPwmChannel, 2);
  290. SetupGpio(3, PortB, NoPwmChannel, 3);
  291. SetupGpio(4, PortB, PwmChannel2A, 4);
  292. SetupGpio(5, PortB, PwmChannel1A, 5);
  293. SetupGpio(6, PortB, PwmChannel1B, 6);
  294. SetupGpio(7, PortB, PwmChannel0A, 7);
  295. SetupGpio(8, PortD, NoPwmChannel, 0);
  296. SetupGpio(9, PortD, NoPwmChannel, 1);
  297. SetupGpio(10, PortD, NoPwmChannel, 2);
  298. SetupGpio(11, PortD, NoPwmChannel, 3);
  299. SetupGpio(12, PortD, NoPwmChannel, 4);
  300. SetupGpio(13, PortD, NoPwmChannel, 5);
  301. SetupGpio(14, PortD, NoPwmChannel, 6);
  302. SetupGpio(15, PortD, NoPwmChannel, 7);
  303. SetupGpio(16, PortC, NoPwmChannel, 0);
  304. SetupGpio(17, PortC, NoPwmChannel, 1);
  305. SetupGpio(18, PortC, NoPwmChannel, 2);
  306. SetupGpio(19, PortC, NoPwmChannel, 3);
  307. SetupGpio(20, PortC, NoPwmChannel, 4);
  308. SetupGpio(21, PortC, NoPwmChannel, 5);
  309. SetupGpio(22, PortC, NoPwmChannel, 6);
  310. SetupGpio(23, PortC, NoPwmChannel, 7);
  311. SetupGpio(24, PortE, NoPwmChannel, 0);
  312. SetupGpio(25, PortE, NoPwmChannel, 1);
  313. SetupGpio(26, PortE, NoPwmChannel, 2);
  314. SetupGpio(27, PortE, NoPwmChannel, 3);
  315. SetupGpio(28, PortE, NoPwmChannel, 4);
  316. SetupGpio(29, PortE, NoPwmChannel, 5);
  317. SetupGpio(30, PortE, NoPwmChannel, 6);
  318. SetupGpio(31, PortE, NoPwmChannel, 7);
  319. SetupGpio(32, PortF, NoPwmChannel, 0);
  320. SetupGpio(33, PortF, NoPwmChannel, 1);
  321. SetupGpio(34, PortF, NoPwmChannel, 2);
  322. SetupGpio(35, PortF, NoPwmChannel, 3);
  323. SetupGpio(36, PortF, NoPwmChannel, 4);
  324. SetupGpio(37, PortF, NoPwmChannel, 5);
  325. SetupGpio(38, PortF, NoPwmChannel, 6);
  326. SetupGpio(39, PortF, NoPwmChannel, 7);
  327. SetupGpio(40, PortG, NoPwmChannel, 0);
  328. SetupGpio(41, PortG, NoPwmChannel, 1);
  329. SetupGpio(42, PortG, NoPwmChannel, 2);
  330. SetupGpio(43, PortG, NoPwmChannel, 3);
  331. SetupGpio(44, PortG, NoPwmChannel, 4);
  332. SetupGpio(45, PortG, NoPwmChannel, 5);
  333. SetupGpio(46, PortG, NoPwmChannel, 6);
  334. SetupGpio(47, PortG, NoPwmChannel, 7);
  335. SetupGpio(48, PortH, NoPwmChannel, 0);
  336. SetupGpio(49, PortH, NoPwmChannel, 1);
  337. SetupGpio(50, PortH, NoPwmChannel, 2);
  338. SetupGpio(51, PortH, NoPwmChannel, 3);
  339. SetupGpio(52, PortH, NoPwmChannel, 4);
  340. SetupGpio(53, PortH, NoPwmChannel, 5);
  341. SetupGpio(54, PortH, NoPwmChannel, 6);
  342. SetupGpio(55, PortH, NoPwmChannel, 7);
  343. SetupGpio(56, PortJ, NoPwmChannel, 0);
  344. SetupGpio(57, PortJ, NoPwmChannel, 1);
  345. SetupGpio(58, PortJ, NoPwmChannel, 2);
  346. SetupGpio(59, PortJ, NoPwmChannel, 3);
  347. SetupGpio(60, PortJ, NoPwmChannel, 4);
  348. SetupGpio(61, PortJ, NoPwmChannel, 5);
  349. SetupGpio(62, PortJ, NoPwmChannel, 6);
  350. SetupGpio(63, PortJ, NoPwmChannel, 7);
  351. SetupGpio(64, PortK, NoPwmChannel, 0);
  352. SetupGpio(65, PortK, NoPwmChannel, 1);
  353. SetupGpio(66, PortK, NoPwmChannel, 2);
  354. SetupGpio(67, PortK, NoPwmChannel, 3);
  355. SetupGpio(68, PortK, NoPwmChannel, 4);
  356. SetupGpio(69, PortK, NoPwmChannel, 5);
  357. SetupGpio(70, PortK, NoPwmChannel, 6);
  358. SetupGpio(71, PortK, NoPwmChannel, 7);
  359. SetupGpio(72, PortL, NoPwmChannel, 0);
  360. SetupGpio(73, PortL, NoPwmChannel, 1);
  361. SetupGpio(74, PortL, NoPwmChannel, 2);
  362. SetupGpio(75, PortL, NoPwmChannel, 3);
  363. SetupGpio(76, PortL, NoPwmChannel, 4);
  364. SetupGpio(77, PortL, NoPwmChannel, 5);
  365. SetupGpio(78, PortL, NoPwmChannel, 6);
  366. SetupGpio(79, PortL, NoPwmChannel, 7);
  367. typedef Gpio<PortB, 0> SpiSS;
  368. typedef Gpio<PortB, 1> SpiSCK;
  369. typedef Gpio<PortB, 2> SpiMOSI;
  370. typedef Gpio<PortB, 3> SpiMISO;
  371. typedef Gpio<PortE, 2> UartSpi0XCK;
  372. typedef Gpio<PortE, 1> UartSpi0TX;
  373. typedef Gpio<PortE, 0> UartSpi0RX;
  374. typedef Gpio<PortD, 5> UartSpi1XCK;
  375. typedef Gpio<PortD, 3> UartSpi1TX;
  376. typedef Gpio<PortD, 2> UartSpi1RX;
  377. typedef Gpio<PortH, 2> UartSpi2XCK;
  378. typedef Gpio<PortH, 1> UartSpi2TX;
  379. typedef Gpio<PortH, 0> UartSpi2RX;
  380. typedef Gpio<PortJ, 2> UartSpi3XCK;
  381. typedef Gpio<PortJ, 1> UartSpi3TX;
  382. typedef Gpio<PortJ, 0> UartSpi3RX;
  383. #define HAS_USART0
  384. #define HAS_USART1
  385. #define HAS_USART2
  386. #define HAS_USART3
  387. #else
  388. #error Unsupported MCU type
  389. #endif
  390. // Two specializations of the numbered pin template, one which clears the timer
  391. // for each access to the PWM pins, as does the original Arduino wire lib,
  392. // the other that does not (use with care!).
  393. template<int n>
  394. struct NumberedGpio {
  395. typedef typename NumberedGpioInternal<n>::Impl Impl;
  396. static void High() { Impl::High(); }
  397. static void Low() { Impl::Low(); }
  398. static void set_mode(uint8_t mode) { Impl::set_mode(mode); }
  399. static void set_value(uint8_t value) { Impl::set_value(value); }
  400. static void set_pwm_value(uint8_t value) { Impl::set_pwm_value(value); }
  401. static uint8_t value() { return Impl::value(); }
  402. };
  403. template<int n>
  404. struct PwmOutput {
  405. enum {
  406. buffer_size = 0,
  407. data_size = 8,
  408. };
  409. static void Init() {
  410. NumberedGpio<n>::set_mode(PWM_OUTPUT);
  411. }
  412. static void Write(uint8_t value) {
  413. return NumberedGpio<n>::set_pwm_value(value);
  414. }
  415. static void Stop() {
  416. NumberedGpio<n>::Impl::Pwm::Stop();
  417. }
  418. static void Start() {
  419. NumberedGpio<n>::Impl::Pwm::Start();
  420. }
  421. };
  422. } // namespace avrlib
  423. #endif // AVRLIB_GPIO_H_