apu.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /* Copyright 2018 Canaan Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. #include <math.h>
  16. #include <stddef.h>
  17. #include <stdint.h>
  18. #include "apu.h"
  19. #include "syscalls.h"
  20. #include "sysctl.h"
  21. #define BEAFORMING_BASE_ADDR (0x50250200)
  22. #ifndef M_PI
  23. #define M_PI 3.14159265358979323846264338327950288
  24. #endif
  25. volatile apu_reg_t *const apu = (volatile apu_reg_t *)BEAFORMING_BASE_ADDR;
  26. /*
  27. Voice strength average value right shift factor. When performing sound direction detect,
  28. the average value of samples from different channels is required, this right shift factor
  29. is used to perform division.
  30. 0x0: no right shift; 0x1: right shift by 1-bit;
  31. . . . . . .
  32. 0xF: right shift by 15-bit.
  33. */
  34. void apu_set_audio_gain(uint16_t gain)
  35. {
  36. apu_ch_cfg_t ch_cfg = apu->bf_ch_cfg_reg;
  37. ch_cfg.we_bf_target_dir = 0;
  38. ch_cfg.we_bf_sound_ch_en = 0;
  39. ch_cfg.we_data_src_mode = 0;
  40. ch_cfg.we_audio_gain = 1;
  41. ch_cfg.audio_gain = gain;
  42. apu->bf_ch_cfg_reg = ch_cfg;
  43. }
  44. /*set sampling shift*/
  45. void apu_set_smpl_shift(uint8_t smpl_shift)
  46. {
  47. apu_dwsz_cfg_t tmp = apu->bf_dwsz_cfg_reg;
  48. tmp.smpl_shift_bits = smpl_shift;
  49. apu->bf_dwsz_cfg_reg = tmp;
  50. }
  51. /*get sampling shift*/
  52. uint8_t apu_get_smpl_shift(void)
  53. {
  54. apu_dwsz_cfg_t tmp = apu->bf_dwsz_cfg_reg;
  55. return tmp.smpl_shift_bits;
  56. }
  57. /*
  58. * APU unit sound channel enable control bits. Bit 'x' corresponds to enable bit for sound
  59. * channel 'x' (x = 0, 1, 2, . . ., 7). APU sound channels are related with I2S host RX channels.
  60. * APU sound channel 0/1 correspond to the left/right channel of I2S RX0; APU channel 2/3 correspond
  61. * to left/right channels of I2S RX1; and things like that. Software write '1' to enable a sound
  62. * channel and hardware automatically clear the bit after the sample buffers used for direction
  63. * searching is filled full.
  64. * 0x1: writing '1' to enable the corresponding APU sound channel.
  65. */
  66. void apu_set_channel_enabled(uint8_t channel_bit)
  67. {
  68. apu_ch_cfg_t ch_cfg;
  69. ch_cfg.we_audio_gain = 0;
  70. ch_cfg.we_bf_target_dir = 0;
  71. ch_cfg.we_bf_sound_ch_en = 1;
  72. ch_cfg.bf_sound_ch_en = channel_bit;
  73. apu->bf_ch_cfg_reg = ch_cfg;
  74. }
  75. /*
  76. * APU unit sound channel enable control bits. Bit 'x' corresponds to enable bit for sound
  77. * channel 'x' (x = 0, 1, 2, . . ., 7). APU sound channels are related with I2S host RX channels.
  78. * APU sound channel 0/1 correspond to the left/right channel of I2S RX0; APU channel 2/3 correspond
  79. * to left/right channels of I2S RX1; and things like that. Software write '1' to enable a sound
  80. * channel and hardware automatically clear the bit after the sample buffers used for direction
  81. * searching is filled full.
  82. * 0x1: writing '1' to enable the corresponding APU sound channel.
  83. */
  84. void apu_channel_enable(uint8_t channel_bit)
  85. {
  86. apu_ch_cfg_t ch_cfg = apu->bf_ch_cfg_reg;
  87. ch_cfg.we_audio_gain = 0;
  88. ch_cfg.we_bf_target_dir = 0;
  89. ch_cfg.we_data_src_mode = 0;
  90. ch_cfg.we_bf_sound_ch_en = 1;
  91. ch_cfg.bf_sound_ch_en = channel_bit;
  92. apu->bf_ch_cfg_reg = ch_cfg;
  93. }
  94. /*
  95. * audio data source configure parameter. This parameter controls where the audio data source comes from.
  96. * 0x0: audio data directly sourcing from apu internal buffer;
  97. * 0x1: audio data sourcing from FFT result buffer.
  98. */
  99. void apu_set_src_mode(uint8_t src_mode)
  100. {
  101. apu_ch_cfg_t ch_cfg = apu->bf_ch_cfg_reg;
  102. ch_cfg.we_audio_gain = 0;
  103. ch_cfg.we_bf_target_dir = 0;
  104. ch_cfg.we_bf_sound_ch_en = 0;
  105. ch_cfg.we_data_src_mode = 1;
  106. ch_cfg.data_src_mode = src_mode;
  107. apu->bf_ch_cfg_reg = ch_cfg;
  108. }
  109. /*
  110. * I2S host beam-forming direction sample ibuffer read index configure register
  111. */
  112. void apu_set_direction_delay(uint8_t dir_num, uint8_t *dir_bidx)
  113. {
  114. apu->bf_dir_bidx[dir_num][0] = (apu_dir_bidx_t){
  115. .dir_rd_idx0 = dir_bidx[0],
  116. .dir_rd_idx1 = dir_bidx[1],
  117. .dir_rd_idx2 = dir_bidx[2],
  118. .dir_rd_idx3 = dir_bidx[3]};
  119. apu->bf_dir_bidx[dir_num][1] = (apu_dir_bidx_t){
  120. .dir_rd_idx0 = dir_bidx[4],
  121. .dir_rd_idx1 = dir_bidx[5],
  122. .dir_rd_idx2 = dir_bidx[6],
  123. .dir_rd_idx3 = dir_bidx[7]};
  124. }
  125. /*
  126. * radius mic_num_a_circle: the num of mic per circle; center: 0: no center mic, 1:have center mic
  127. */
  128. void apu_set_delay(float radius, uint8_t mic_num_a_circle, uint8_t center)
  129. {
  130. uint8_t offsets[16][8];
  131. int i, j;
  132. float seta[8], delay[8], hudu_jiao;
  133. float cm_tick = (float)SOUND_SPEED * 100 / I2S_FS; /*distance per tick (cm)*/
  134. float min;
  135. for(i = 0; i < mic_num_a_circle; ++i)
  136. {
  137. seta[i] = 360 * i / mic_num_a_circle;
  138. hudu_jiao = 2 * M_PI * seta[i] / 360;
  139. delay[i] = radius * (1 - cos(hudu_jiao)) / cm_tick;
  140. }
  141. if(center)
  142. delay[mic_num_a_circle] = radius / cm_tick;
  143. for(i = 0; i < mic_num_a_circle + center; ++i)
  144. {
  145. offsets[0][i] = (int)(delay[i] + 0.5);
  146. }
  147. for(; i < 8; i++)
  148. offsets[0][i] = 0;
  149. for(j = 1; j < DIRECTION_RES; ++j)
  150. {
  151. for(i = 0; i < mic_num_a_circle; ++i)
  152. {
  153. seta[i] -= 360 / DIRECTION_RES;
  154. hudu_jiao = 2 * M_PI * seta[i] / 360;
  155. delay[i] = radius * (1 - cos(hudu_jiao)) / cm_tick;
  156. }
  157. if(center)
  158. delay[mic_num_a_circle] = radius / cm_tick;
  159. min = 2 * radius;
  160. for(i = 0; i < mic_num_a_circle; ++i)
  161. {
  162. if(delay[i] < min)
  163. min = delay[i];
  164. }
  165. if(min)
  166. {
  167. for(i = 0; i < mic_num_a_circle + center; ++i)
  168. {
  169. delay[i] = delay[i] - min;
  170. }
  171. }
  172. for(i = 0; i < mic_num_a_circle + center; ++i)
  173. {
  174. offsets[j][i] = (int)(delay[i] + 0.5);
  175. }
  176. for(; i < 8; i++)
  177. offsets[0][i] = 0;
  178. }
  179. for(size_t i = 0; i < DIRECTION_RES; i++)
  180. {
  181. apu_set_direction_delay(i, offsets[i]);
  182. }
  183. }
  184. /*
  185. Sound direction searching enable bit. Software writes '1' to start sound direction searching function.
  186. When all the sound sample buffers are filled full, this bit is cleared by hardware (this sample buffers
  187. are used for direction detect only).
  188. 0x1: enable direction searching.
  189. */
  190. void apu_dir_enable(void)
  191. {
  192. apu_ctl_t bf_en_tmp = apu->bf_ctl_reg;
  193. bf_en_tmp.we_bf_dir_search_en = 1;
  194. bf_en_tmp.bf_dir_search_en = 1;
  195. apu->bf_ctl_reg = bf_en_tmp;
  196. }
  197. void apu_dir_reset(void)
  198. {
  199. apu_ctl_t bf_en_tmp = apu->bf_ctl_reg;
  200. bf_en_tmp.we_search_path_rst = 1;
  201. bf_en_tmp.search_path_reset = 1;
  202. apu->bf_ctl_reg = bf_en_tmp;
  203. }
  204. /*
  205. Valid voice sample stream generation enable bit. After sound direction searching is done, software can
  206. configure this bit to generate a stream of voice samples for voice recognition.
  207. 0x1: enable output of voice sample stream.
  208. 0x0: stop the voice samlpe stream output.
  209. */
  210. void apu_voc_enable(uint8_t enable_flag)
  211. {
  212. apu_ctl_t bf_en_tmp = apu->bf_ctl_reg;
  213. bf_en_tmp.we_bf_stream_gen = 1;
  214. bf_en_tmp.bf_stream_gen_en = enable_flag;
  215. apu->bf_ctl_reg = bf_en_tmp;
  216. }
  217. void apu_voc_reset(void)
  218. {
  219. apu_ctl_t bf_en_tmp = apu->bf_ctl_reg;
  220. bf_en_tmp.we_voice_gen_path_rst = 1;
  221. bf_en_tmp.voice_gen_path_reset = 1;
  222. apu->bf_ctl_reg = bf_en_tmp;
  223. }
  224. /*
  225. Target direction select for valid voice output. When the source voice direaction searching
  226. is done, software can use this field to select one from 16 sound directions for the following
  227. voice recognition
  228. 0x0: select sound direction 0; 0x1: select sound direction 1;
  229. . . . . . .
  230. 0xF: select sound direction 15.
  231. */
  232. void apu_voc_set_direction(en_bf_dir_t direction)
  233. {
  234. apu_ch_cfg_t ch_cfg = apu->bf_ch_cfg_reg;
  235. ch_cfg.we_bf_sound_ch_en = 0;
  236. ch_cfg.we_audio_gain = 0;
  237. ch_cfg.we_data_src_mode = 0;
  238. ch_cfg.we_bf_target_dir = 1;
  239. ch_cfg.bf_target_dir = direction;
  240. apu->bf_ch_cfg_reg = ch_cfg;
  241. apu_ctl_t bf_en_tmp = apu->bf_ctl_reg;
  242. bf_en_tmp.we_update_voice_dir = 1;
  243. bf_en_tmp.update_voice_dir = 1;
  244. apu->bf_ctl_reg = bf_en_tmp;
  245. }
  246. /*
  247. *I2S host beam-forming Filter FIR16 Coefficient Register
  248. */
  249. void apu_dir_set_prev_fir(uint16_t *fir_coef)
  250. {
  251. uint8_t i = 0;
  252. for(i = 0; i < 9; i++)
  253. {
  254. apu->bf_pre_fir0_coef[i] =
  255. (apu_fir_coef_t){
  256. .fir_tap0 = fir_coef[i * 2],
  257. .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]};
  258. }
  259. }
  260. void apu_dir_set_post_fir(uint16_t *fir_coef)
  261. {
  262. uint8_t i = 0;
  263. for(i = 0; i < 9; i++)
  264. {
  265. apu->bf_post_fir0_coef[i] =
  266. (apu_fir_coef_t){
  267. .fir_tap0 = fir_coef[i * 2],
  268. .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]};
  269. }
  270. }
  271. void apu_voc_set_prev_fir(uint16_t *fir_coef)
  272. {
  273. uint8_t i = 0;
  274. for(i = 0; i < 9; i++)
  275. {
  276. apu->bf_pre_fir1_coef[i] =
  277. (apu_fir_coef_t){
  278. .fir_tap0 = fir_coef[i * 2],
  279. .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]};
  280. }
  281. }
  282. void apu_voc_set_post_fir(uint16_t *fir_coef)
  283. {
  284. uint8_t i = 0;
  285. for(i = 0; i < 9; i++)
  286. {
  287. apu->bf_post_fir1_coef[i] =
  288. (apu_fir_coef_t){
  289. .fir_tap0 = fir_coef[i * 2],
  290. .fir_tap1 = i == 8 ? 0 : fir_coef[i * 2 + 1]};
  291. }
  292. }
  293. void apu_set_fft_shift_factor(uint8_t enable_flag, uint16_t shift_factor)
  294. {
  295. apu->bf_fft_cfg_reg =
  296. (apu_fft_cfg_t){
  297. .fft_enable = enable_flag,
  298. .fft_shift_factor = shift_factor};
  299. apu_ch_cfg_t ch_cfg = apu->bf_ch_cfg_reg;
  300. ch_cfg.we_data_src_mode = 1;
  301. ch_cfg.data_src_mode = enable_flag;
  302. apu->bf_ch_cfg_reg = ch_cfg;
  303. }
  304. void apu_dir_set_down_size(uint8_t dir_dwn_size)
  305. {
  306. apu_dwsz_cfg_t tmp = apu->bf_dwsz_cfg_reg;
  307. tmp.dir_dwn_siz_rate = dir_dwn_size;
  308. apu->bf_dwsz_cfg_reg = tmp;
  309. }
  310. void apu_dir_set_interrupt_mask(uint8_t dir_int_mask)
  311. {
  312. apu_int_mask_t tmp = apu->bf_int_mask_reg;
  313. tmp.dir_data_rdy_msk = dir_int_mask;
  314. apu->bf_int_mask_reg = tmp;
  315. }
  316. void apu_voc_set_down_size(uint8_t voc_dwn_size)
  317. {
  318. apu_dwsz_cfg_t tmp = apu->bf_dwsz_cfg_reg;
  319. tmp.voc_dwn_siz_rate = voc_dwn_size;
  320. apu->bf_dwsz_cfg_reg = tmp;
  321. }
  322. void apu_voc_set_interrupt_mask(uint8_t voc_int_mask)
  323. {
  324. apu_int_mask_t tmp = apu->bf_int_mask_reg;
  325. tmp.voc_buf_rdy_msk = voc_int_mask;
  326. apu->bf_int_mask_reg = tmp;
  327. }
  328. void apu_set_down_size(uint8_t dir_dwn_size, uint8_t voc_dwn_size)
  329. {
  330. apu_dwsz_cfg_t tmp = apu->bf_dwsz_cfg_reg;
  331. tmp.dir_dwn_siz_rate = dir_dwn_size;
  332. tmp.voc_dwn_siz_rate = voc_dwn_size;
  333. apu->bf_dwsz_cfg_reg = tmp;
  334. }
  335. void apu_set_interrupt_mask(uint8_t dir_int_mask, uint8_t voc_int_mask)
  336. {
  337. apu->bf_int_mask_reg =
  338. (apu_int_mask_t){
  339. .dir_data_rdy_msk = dir_int_mask,
  340. .voc_buf_rdy_msk = voc_int_mask};
  341. }
  342. void apu_dir_clear_int_state(void)
  343. {
  344. apu->bf_int_stat_reg =
  345. (apu_int_stat_t){
  346. .dir_search_data_rdy = 1};
  347. }
  348. void apu_voc_clear_int_state(void)
  349. {
  350. apu->bf_int_stat_reg =
  351. (apu_int_stat_t){
  352. .voc_buf_data_rdy = 1};
  353. }
  354. /* reset saturation_counter */
  355. void apu_voc_reset_saturation_counter(void)
  356. {
  357. apu->saturation_counter = 1 << 31;
  358. }
  359. /*get saturation counter*/
  360. /*heigh 16 bit is counter, low 16 bit is total.*/
  361. uint32_t apu_voc_get_saturation_counter(void)
  362. {
  363. return apu->saturation_counter;
  364. }
  365. /*set saturation limit*/
  366. void apu_voc_set_saturation_limit(uint16_t upper, uint16_t bottom)
  367. {
  368. apu->saturation_limits = (uint32_t)bottom << 16 | upper;
  369. }
  370. /*get saturation limit*/
  371. /*heigh 16 bit is counter, low 16 bit is total.*/
  372. uint32_t apu_voc_get_saturation_limit(void)
  373. {
  374. return apu->saturation_limits;
  375. }
  376. static void print_fir(const char *member_name, volatile apu_fir_coef_t *pfir)
  377. {
  378. printf(" for(int i = 0; i < 9; i++){\n");
  379. for(int i = 0; i < 9; i++)
  380. {
  381. apu_fir_coef_t fir = pfir[i];
  382. printf(" apu->%s[%d] = (apu_fir_coef_t){\n", member_name, i);
  383. printf(" .fir_tap0 = 0x%x,\n", fir.fir_tap0);
  384. printf(" .fir_tap1 = 0x%x\n", fir.fir_tap1);
  385. printf(" };\n");
  386. }
  387. printf(" }\n");
  388. }
  389. void apu_print_setting(void)
  390. {
  391. printf("void apu_setting(void) {\n");
  392. apu_ch_cfg_t bf_ch_cfg_reg = apu->bf_ch_cfg_reg;
  393. printf(" apu->bf_ch_cfg_reg = (apu_ch_cfg_t){\n");
  394. printf(" .we_audio_gain = 1, .we_bf_target_dir = 1, .we_bf_sound_ch_en = 1,\n");
  395. printf(" .audio_gain = 0x%x, .bf_target_dir = %d, .bf_sound_ch_en = %d, .data_src_mode = %d\n",
  396. bf_ch_cfg_reg.audio_gain, bf_ch_cfg_reg.bf_target_dir, bf_ch_cfg_reg.bf_sound_ch_en, bf_ch_cfg_reg.data_src_mode);
  397. printf(" };\n");
  398. apu_ctl_t bf_ctl_reg = apu->bf_ctl_reg;
  399. printf(" apu->bf_ctl_reg = (apu_ctl_t){\n");
  400. printf(" .we_bf_stream_gen = 1, .we_bf_dir_search_en = 1,\n");
  401. printf(" .bf_stream_gen_en = %d, .bf_dir_search_en = %d\n",
  402. bf_ctl_reg.bf_stream_gen_en, bf_ctl_reg.bf_dir_search_en);
  403. printf(" };\n");
  404. printf(" for(int i = 0; i < 16; i++){\n");
  405. for(int i = 0; i < 16; i++)
  406. {
  407. apu_dir_bidx_t bidx0 = apu->bf_dir_bidx[i][0];
  408. apu_dir_bidx_t bidx1 = apu->bf_dir_bidx[i][1];
  409. printf(" apu->bf_dir_bidx[%d][0] = (apu_dir_bidx_t){\n", i);
  410. printf(" .dir_rd_idx0 = 0x%x,\n", bidx0.dir_rd_idx0);
  411. printf(" .dir_rd_idx1 = 0x%x,\n", bidx0.dir_rd_idx1);
  412. printf(" .dir_rd_idx2 = 0x%x,\n", bidx0.dir_rd_idx2);
  413. printf(" .dir_rd_idx3 = 0x%x\n", bidx0.dir_rd_idx3);
  414. printf(" };\n");
  415. printf(" apu->bf_dir_bidx[%d][1] = (apu_dir_bidx_t){\n", i);
  416. printf(" .dir_rd_idx0 = 0x%x,\n", bidx1.dir_rd_idx0);
  417. printf(" .dir_rd_idx1 = 0x%x,\n", bidx1.dir_rd_idx1);
  418. printf(" .dir_rd_idx2 = 0x%x,\n", bidx1.dir_rd_idx2);
  419. printf(" .dir_rd_idx3 = 0x%x\n", bidx1.dir_rd_idx3);
  420. printf(" };\n");
  421. }
  422. printf(" }\n");
  423. print_fir("bf_pre_fir0_coef", apu->bf_pre_fir0_coef);
  424. print_fir("bf_post_fir0_coef", apu->bf_post_fir0_coef);
  425. print_fir("bf_pre_fir1_coef", apu->bf_pre_fir1_coef);
  426. print_fir("bf_post_fir1_coef", apu->bf_post_fir1_coef);
  427. apu_dwsz_cfg_t bf_dwsz_cfg_reg = apu->bf_dwsz_cfg_reg;
  428. printf(" apu->bf_dwsz_cfg_reg = (apu_dwsz_cfg_t){\n");
  429. printf(" .dir_dwn_siz_rate = %d, .voc_dwn_siz_rate = %d\n",
  430. bf_dwsz_cfg_reg.dir_dwn_siz_rate, bf_dwsz_cfg_reg.voc_dwn_siz_rate);
  431. printf(" };\n");
  432. apu_fft_cfg_t bf_fft_cfg_reg = apu->bf_fft_cfg_reg;
  433. printf(" apu->bf_fft_cfg_reg = (apu_fft_cfg_t){\n");
  434. printf(" .fft_enable = %d, .fft_shift_factor = 0x%x\n",
  435. bf_fft_cfg_reg.fft_enable, bf_fft_cfg_reg.fft_shift_factor);
  436. printf(" };\n");
  437. apu_int_mask_t bf_int_mask_reg = apu->bf_int_mask_reg;
  438. printf(" apu->bf_int_mask_reg = (apu_int_mask_t){\n");
  439. printf(" .dir_data_rdy_msk = %d, .voc_buf_rdy_msk = %d\n",
  440. bf_int_mask_reg.dir_data_rdy_msk, bf_int_mask_reg.voc_buf_rdy_msk);
  441. printf(" };\n");
  442. printf("}\n");
  443. }