ARM7 based quadrocopter
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.
 
 
 
 
 

330 lines
8.5 KiB

  1. /***************************************************************************
  2. * sam7fc - TWI/I2C Handling *
  3. * *
  4. * Copyright (C) 02/2008 by Olaf Rempel *
  5. * razzor@kopf-tisch.de *
  6. * *
  7. * This program is free software; you can redistribute it and/or modify *
  8. * it under the terms of the GNU General Public License as published by *
  9. * the Free Software Foundation; version 2 of the License *
  10. * *
  11. * This program is distributed in the hope that it will be useful, *
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  14. * GNU General Public License for more details. *
  15. * *
  16. * You should have received a copy of the GNU General Public License *
  17. * along with this program; if not, write to the *
  18. * Free Software Foundation, Inc., *
  19. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  20. ***************************************************************************/
  21. #include <stdint.h>
  22. #include <stdio.h>
  23. #include "AT91SAM7S256.h"
  24. #include "board.h"
  25. #include "at91_twi.h"
  26. /*
  27. * undocumented TWI_SR flags, at least OVRE seems to be present on a sam7s256
  28. * taken from linux-2.6.24/include/asm-arm/arch-at91/at91_twi.h
  29. */
  30. #define AT91_TWI_OVRE (1<<6) /* Overrun */
  31. #define AT91_TWI_UNRE (1<<7) /* Underrun */
  32. /*
  33. * while ((cldiv = ((MCK / (2 * TWI)) -3) / (1 << ckdiv)) > 255)
  34. * ckdiv++ ;
  35. *
  36. * works for TWI >= 100kHz
  37. */
  38. #define TWI_CLK(x) (((MCK / (2 * (x))) -3)<<8 | ((MCK / (2 * (x))) -3))
  39. enum twi_states {
  40. TWI_IDLE = 0x00,
  41. TWI_ERROR,
  42. TWI_GENERIC_CMD = 0x10,
  43. TWI_BLMC_UPDATE = 0x20,
  44. };
  45. static volatile uint32_t twi_state = TWI_IDLE;
  46. static uint8_t *twi_data;
  47. static uint32_t twi_size;
  48. static uint32_t twi_count;
  49. static void twi_isr(void)
  50. {
  51. /* get status */
  52. uint32_t status = *AT91C_TWI_SR;
  53. status &= *AT91C_TWI_IMR;
  54. /* NACK - disable all interrupts and go to state TWI_ERROR */
  55. if (status & AT91C_TWI_NACK) {
  56. *AT91C_TWI_IDR = AT91C_TWI_TXCOMP | AT91C_TWI_RXRDY | AT91C_TWI_TXRDY | AT91C_TWI_NACK;
  57. twi_state = TWI_ERROR;
  58. return;
  59. }
  60. /* tx register ready for new data */
  61. if (status & AT91C_TWI_TXRDY) {
  62. if (twi_count != twi_size) {
  63. /* feed next byte */
  64. *AT91C_TWI_THR = twi_data[twi_count++];
  65. } else {
  66. /* wait for TXCOMP */
  67. *AT91C_TWI_IDR = AT91C_TWI_RXRDY | AT91C_TWI_TXRDY;
  68. *AT91C_TWI_IER = AT91C_TWI_TXCOMP | AT91C_TWI_NACK;
  69. }
  70. }
  71. /* rx register has data */
  72. if (status & AT91C_TWI_RXRDY) {
  73. /* get data */
  74. twi_data[twi_count++] = *AT91C_TWI_RHR;
  75. /* transfer complete? */
  76. if (twi_count == twi_size) {
  77. /* send STOP and wait for TXCOMP */
  78. *AT91C_TWI_CR = AT91C_TWI_STOP;
  79. *AT91C_TWI_IDR = AT91C_TWI_TXRDY;
  80. *AT91C_TWI_IER = AT91C_TWI_TXCOMP | AT91C_TWI_NACK;
  81. }
  82. }
  83. /* transfer really complete? */
  84. if (status & AT91C_TWI_TXCOMP) {
  85. uint32_t addr = (*AT91C_TWI_MMR >> 16) & 0x7F;
  86. /* are we doing a blmc update? */
  87. if (twi_state == TWI_BLMC_UPDATE && addr != TWI_ADDR_BL4) {
  88. /* increase address */
  89. *AT91C_TWI_MMR += (1<<16);
  90. /* send next value to next blmc */
  91. *AT91C_TWI_THR = *twi_data++;
  92. } else {
  93. *AT91C_TWI_IDR = AT91C_TWI_TXCOMP | AT91C_TWI_RXRDY | AT91C_TWI_TXRDY | AT91C_TWI_NACK;
  94. twi_state = TWI_IDLE;
  95. }
  96. }
  97. }
  98. uint32_t twi_setpwm(uint8_t *values)
  99. {
  100. if (twi_state == TWI_ERROR)
  101. twi_state = TWI_IDLE;
  102. if (twi_state != TWI_IDLE)
  103. return 1;
  104. twi_state = TWI_BLMC_UPDATE;
  105. twi_data = values;
  106. twi_size = 0;
  107. twi_count = 0;
  108. *AT91C_TWI_MMR = (TWI_ADDR_BL1 << 16) | AT91C_TWI_IADRSZ_1_BYTE;
  109. *AT91C_TWI_IADR = CMD_SET_PWM;
  110. *AT91C_TWI_THR = *twi_data++;
  111. *AT91C_TWI_IER = AT91C_TWI_TXRDY | AT91C_TWI_NACK;
  112. return 0;
  113. }
  114. uint32_t twi_cmd(uint8_t addr, struct twi_cmd *cmd)
  115. {
  116. if (twi_state == TWI_ERROR)
  117. twi_state = TWI_IDLE;
  118. if (twi_state != TWI_IDLE)
  119. return 1;
  120. /* TODO: locking needed? */
  121. twi_state = TWI_GENERIC_CMD;
  122. /* read transfer, or write transfer with payload */
  123. if (cmd->mode & TWI_MODE_READ || cmd->size != 0) {
  124. /* set address, direction, argument count and command bytes */
  125. *AT91C_TWI_MMR = (addr << 16) | (cmd->mode & 0xFF) << 8;
  126. *AT91C_TWI_IADR = cmd->cmd;
  127. /* write transfer without payload */
  128. } else {
  129. /* use one cmd byte as payload (needed to start transfer) */
  130. cmd->mode--;
  131. *AT91C_TWI_MMR = (addr << 16) | (cmd->mode & 0xFF) << 8;
  132. *AT91C_TWI_IADR = (cmd->cmd) >> 8;
  133. }
  134. /* isr needs data & size parameters */
  135. twi_data = cmd->data;
  136. twi_size = cmd->size;
  137. twi_count = 0;
  138. if (cmd->mode & TWI_MODE_READ) {
  139. *AT91C_TWI_CR = AT91C_TWI_START;
  140. *AT91C_TWI_IER = AT91C_TWI_RXRDY | AT91C_TWI_NACK;
  141. } else {
  142. *AT91C_TWI_THR = (twi_size != 0) ? cmd->data[twi_count++] : (cmd->cmd & 0xFF);
  143. *AT91C_TWI_IER = AT91C_TWI_TXRDY | AT91C_TWI_NACK;
  144. }
  145. /*
  146. * wait for end
  147. * TODO: locking needed?
  148. * TODO: timeout?
  149. */
  150. while (twi_state != TWI_IDLE && twi_state != TWI_ERROR);
  151. if (twi_state != TWI_IDLE) {
  152. twi_state = TWI_IDLE;
  153. return 1;
  154. }
  155. return 0;
  156. }
  157. uint32_t twi_read_eeprom(uint32_t addr, uint8_t *buf, uint32_t size)
  158. {
  159. struct twi_cmd cmd = {
  160. .cmd = (addr & 0x7FFF),
  161. .mode = TWI_MODE_READ | TWI_MODE_1_ARG,
  162. .size = (size & 0x7FFF),
  163. .data = buf,
  164. };
  165. if (twi_cmd(TWI_ADDR_EEPROM, &cmd) != 0)
  166. size = 0;
  167. return size;
  168. }
  169. uint32_t twi_write_eeprom(uint32_t addr, uint8_t *buf, uint32_t size)
  170. {
  171. uint32_t len = size;
  172. while (len > 0) {
  173. uint32_t count = 0x40 - (addr & 0x3F);
  174. if (count > len)
  175. count = len;
  176. /* TODO: write complete polling */
  177. volatile uint32_t x;
  178. for (x = 0; x < 200000; x++);
  179. struct twi_cmd cmd = {
  180. .cmd = (addr & 0x7FFF),
  181. .mode = TWI_MODE_WRITE | TWI_MODE_1_ARG,
  182. .size = count,
  183. .data = buf,
  184. };
  185. if (twi_cmd(TWI_ADDR_EEPROM, &cmd) != 0)
  186. break;
  187. addr += count;
  188. buf += count;
  189. len -= count;
  190. }
  191. return size - len;
  192. }
  193. void at91_twi_test(void)
  194. {
  195. uint32_t i;
  196. for (i = TWI_ADDR_BL1; i <= TWI_ADDR_BL4; i++) {
  197. printf("twi[0x%02lx] ", i);
  198. struct twi_cmd cmd = {
  199. .cmd = CMD_BOOT_LOADER,
  200. .mode = TWI_MODE_WRITE | TWI_MODE_0_ARG,
  201. };
  202. twi_cmd(i, &cmd);
  203. /* TODO: sleep */
  204. volatile uint32_t x;
  205. for (x = 0; x < 200000; x++);
  206. uint8_t buf[16];
  207. buf[0] = '\0';
  208. cmd.cmd = CMD_GET_INFO;
  209. cmd.mode = TWI_MODE_READ | TWI_MODE_0_ARG;
  210. cmd.size = sizeof(buf);
  211. cmd.data = buf;
  212. twi_cmd(i, &cmd);
  213. printf("boot:'%s' ", buf);
  214. /* TODO: single 32bit write */
  215. buf[0] = 0xFF;
  216. buf[1] = 0xFF;
  217. buf[2] = 0xFF;
  218. cmd.cmd = CMD_GET_SIGNATURE;
  219. cmd.size = 4;
  220. twi_cmd(i, &cmd);
  221. printf("sig:0x%02x%02x%02x\n\r", buf[0], buf[1], buf[2]);
  222. cmd.cmd = CMD_BOOT_APPLICATION;
  223. cmd.mode = TWI_MODE_WRITE | TWI_MODE_0_ARG;
  224. cmd.size = 0;
  225. twi_cmd(i, &cmd);
  226. /* TODO: sleep */
  227. for (x = 0; x < 200000; x++);
  228. buf[0] = '\0';
  229. cmd.cmd = CMD_GET_INFO;
  230. cmd.mode = TWI_MODE_READ | TWI_MODE_0_ARG;
  231. cmd.size = sizeof(buf);
  232. cmd.data = buf;
  233. twi_cmd(i, &cmd);
  234. printf(" app :'%s' ", buf);
  235. struct blmc_param param;
  236. cmd.cmd = CMD_GET_PARAM;
  237. cmd.mode = TWI_MODE_READ | TWI_MODE_0_ARG;
  238. cmd.size = sizeof(param);
  239. cmd.data = (uint8_t *)&param;
  240. twi_cmd(i, &cmd);
  241. printf("pwm:0x%02x-0x%02x Ilimit:0x%03x Imax:0x%03x\n\r",
  242. param.pwm_min, param.pwm_max,
  243. param.current_limit, param.current_max);
  244. }
  245. }
  246. void at91_twi_init(void)
  247. {
  248. /* enable Clock */
  249. *AT91C_PMC_PCER = (1 << AT91C_ID_TWI);
  250. /* SDA & SCL from Peripheral A, Open Drain, no Pullup */
  251. AT91S_PIO *pio = AT91C_BASE_PIOA;
  252. /* do a software reset (bus not connected) */
  253. *AT91C_TWI_CR = AT91C_TWI_SWRST;
  254. pio->PIO_MDER = AT91C_PA3_TWD | AT91C_PA4_TWCK;
  255. pio->PIO_PPUDR = AT91C_PA3_TWD | AT91C_PA4_TWCK;
  256. pio->PIO_ASR = AT91C_PA3_TWD | AT91C_PA4_TWCK;
  257. pio->PIO_PDR = AT91C_PA3_TWD | AT91C_PA4_TWCK;
  258. /* set TWI Clock */
  259. *AT91C_TWI_CWGR = TWI_CLK(400000); //| (5<<16);
  260. /* disable all (known) interrupts */
  261. *AT91C_TWI_IDR = AT91C_TWI_TXCOMP | AT91C_TWI_RXRDY | AT91C_TWI_TXRDY | AT91C_TWI_NACK;
  262. /* level triggered, own vector */
  263. AT91S_AIC *aic = AT91C_BASE_AIC;
  264. aic->AIC_SMR[AT91C_ID_TWI] = IRQPRIO_TWI | AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL;
  265. aic->AIC_SVR[AT91C_ID_TWI] = (uint32_t)twi_isr;
  266. aic->AIC_IECR = (1 << AT91C_ID_TWI);
  267. /* enable teh monster */
  268. *AT91C_TWI_CR = AT91C_TWI_MSEN;
  269. }