main.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /**
  2. * Copyright (c) 2015 - 2020, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. /** @file
  41. * @defgroup i2s_example_main main.c
  42. * @{
  43. * @ingroup i2s_example
  44. *
  45. * @brief I2S Example Application main file.
  46. *
  47. * This file contains the source code for a sample application using I2S.
  48. */
  49. #include <stdio.h>
  50. #include "nrf_drv_i2s.h"
  51. #include "nrf_delay.h"
  52. #include "app_util_platform.h"
  53. #include "app_error.h"
  54. #include "boards.h"
  55. #include "nrf_log.h"
  56. #include "nrf_log_ctrl.h"
  57. #include "nrf_log_default_backends.h"
  58. #define LED_OK BSP_BOARD_LED_0
  59. #define LED_ERROR BSP_BOARD_LED_1
  60. #define I2S_DATA_BLOCK_WORDS 512
  61. static uint32_t m_buffer_rx[2][I2S_DATA_BLOCK_WORDS];
  62. static uint32_t m_buffer_tx[2][I2S_DATA_BLOCK_WORDS];
  63. // Delay time between consecutive I2S transfers performed in the main loop
  64. // (in milliseconds).
  65. #define PAUSE_TIME 500
  66. // Number of blocks of data to be contained in each transfer.
  67. #define BLOCKS_TO_TRANSFER 20
  68. static uint8_t volatile m_blocks_transferred = 0;
  69. static uint8_t m_zero_samples_to_ignore = 0;
  70. static uint16_t m_sample_value_to_send;
  71. static uint16_t m_sample_value_expected;
  72. static bool m_error_encountered;
  73. static uint32_t * volatile mp_block_to_fill = NULL;
  74. static uint32_t const * volatile mp_block_to_check = NULL;
  75. static void prepare_tx_data(uint32_t * p_block)
  76. {
  77. // These variables will be both zero only at the very beginning of each
  78. // transfer, so we use them as the indication that the re-initialization
  79. // should be performed.
  80. if (m_blocks_transferred == 0 && m_zero_samples_to_ignore == 0)
  81. {
  82. // Number of initial samples (actually pairs of L/R samples) with zero
  83. // values that should be ignored - see the comment in 'check_samples'.
  84. m_zero_samples_to_ignore = 2;
  85. m_sample_value_to_send = 0xCAFE;
  86. m_sample_value_expected = 0xCAFE;
  87. m_error_encountered = false;
  88. }
  89. // [each data word contains two 16-bit samples]
  90. uint16_t i;
  91. for (i = 0; i < I2S_DATA_BLOCK_WORDS; ++i)
  92. {
  93. uint16_t sample_l = m_sample_value_to_send - 1;
  94. uint16_t sample_r = m_sample_value_to_send + 1;
  95. ++m_sample_value_to_send;
  96. uint32_t * p_word = &p_block[i];
  97. ((uint16_t *)p_word)[0] = sample_l;
  98. ((uint16_t *)p_word)[1] = sample_r;
  99. }
  100. }
  101. static bool check_samples(uint32_t const * p_block)
  102. {
  103. // [each data word contains two 16-bit samples]
  104. uint16_t i;
  105. for (i = 0; i < I2S_DATA_BLOCK_WORDS; ++i)
  106. {
  107. uint32_t const * p_word = &p_block[i];
  108. uint16_t actual_sample_l = ((uint16_t const *)p_word)[0];
  109. uint16_t actual_sample_r = ((uint16_t const *)p_word)[1];
  110. // Normally a couple of initial samples sent by the I2S peripheral
  111. // will have zero values, because it starts to output the clock
  112. // before the actual data is fetched by EasyDMA. As we are dealing
  113. // with streaming the initial zero samples can be simply ignored.
  114. if (m_zero_samples_to_ignore > 0 &&
  115. actual_sample_l == 0 &&
  116. actual_sample_r == 0)
  117. {
  118. --m_zero_samples_to_ignore;
  119. }
  120. else
  121. {
  122. m_zero_samples_to_ignore = 0;
  123. uint16_t expected_sample_l = m_sample_value_expected - 1;
  124. uint16_t expected_sample_r = m_sample_value_expected + 1;
  125. ++m_sample_value_expected;
  126. if (actual_sample_l != expected_sample_l ||
  127. actual_sample_r != expected_sample_r)
  128. {
  129. NRF_LOG_INFO("%3u: %04x/%04x, expected: %04x/%04x (i: %u)",
  130. m_blocks_transferred, actual_sample_l, actual_sample_r,
  131. expected_sample_l, expected_sample_r, i);
  132. return false;
  133. }
  134. }
  135. }
  136. NRF_LOG_INFO("%3u: OK", m_blocks_transferred);
  137. return true;
  138. }
  139. static void check_rx_data(uint32_t const * p_block)
  140. {
  141. ++m_blocks_transferred;
  142. if (!m_error_encountered)
  143. {
  144. m_error_encountered = !check_samples(p_block);
  145. }
  146. if (m_error_encountered)
  147. {
  148. bsp_board_led_off(LED_OK);
  149. bsp_board_led_invert(LED_ERROR);
  150. }
  151. else
  152. {
  153. bsp_board_led_off(LED_ERROR);
  154. bsp_board_led_invert(LED_OK);
  155. }
  156. }
  157. static void data_handler(nrf_drv_i2s_buffers_t const * p_released,
  158. uint32_t status)
  159. {
  160. // 'nrf_drv_i2s_next_buffers_set' is called directly from the handler
  161. // each time next buffers are requested, so data corruption is not
  162. // expected.
  163. ASSERT(p_released);
  164. // When the handler is called after the transfer has been stopped
  165. // (no next buffers are needed, only the used buffers are to be
  166. // released), there is nothing to do.
  167. if (!(status & NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED))
  168. {
  169. return;
  170. }
  171. // First call of this handler occurs right after the transfer is started.
  172. // No data has been transferred yet at this point, so there is nothing to
  173. // check. Only the buffers for the next part of the transfer should be
  174. // provided.
  175. if (!p_released->p_rx_buffer)
  176. {
  177. nrf_drv_i2s_buffers_t const next_buffers = {
  178. .p_rx_buffer = m_buffer_rx[1],
  179. .p_tx_buffer = m_buffer_tx[1],
  180. };
  181. APP_ERROR_CHECK(nrf_drv_i2s_next_buffers_set(&next_buffers));
  182. mp_block_to_fill = m_buffer_tx[1];
  183. }
  184. else
  185. {
  186. mp_block_to_check = p_released->p_rx_buffer;
  187. // The driver has just finished accessing the buffers pointed by
  188. // 'p_released'. They can be used for the next part of the transfer
  189. // that will be scheduled now.
  190. APP_ERROR_CHECK(nrf_drv_i2s_next_buffers_set(p_released));
  191. // The pointer needs to be typecasted here, so that it is possible to
  192. // modify the content it is pointing to (it is marked in the structure
  193. // as pointing to constant data because the driver is not supposed to
  194. // modify the provided data).
  195. mp_block_to_fill = (uint32_t *)p_released->p_tx_buffer;
  196. }
  197. }
  198. void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
  199. {
  200. bsp_board_leds_on();
  201. app_error_save_and_stop(id, pc, info);
  202. }
  203. int main(void)
  204. {
  205. uint32_t err_code = NRF_SUCCESS;
  206. bsp_board_init(BSP_INIT_LEDS);
  207. err_code = NRF_LOG_INIT(NULL);
  208. APP_ERROR_CHECK(err_code);
  209. NRF_LOG_DEFAULT_BACKENDS_INIT();
  210. NRF_LOG_INFO("I2S loopback example started.");
  211. nrf_drv_i2s_config_t config = NRF_DRV_I2S_DEFAULT_CONFIG;
  212. // In Master mode the MCK frequency and the MCK/LRCK ratio should be
  213. // set properly in order to achieve desired audio sample rate (which
  214. // is equivalent to the LRCK frequency).
  215. // For the following settings we'll get the LRCK frequency equal to
  216. // 15873 Hz (the closest one to 16 kHz that is possible to achieve).
  217. config.sdin_pin = I2S_SDIN_PIN;
  218. config.sdout_pin = I2S_SDOUT_PIN;
  219. config.mck_setup = NRF_I2S_MCK_32MDIV21;
  220. config.ratio = NRF_I2S_RATIO_96X;
  221. config.channels = NRF_I2S_CHANNELS_STEREO;
  222. err_code = nrf_drv_i2s_init(&config, data_handler);
  223. APP_ERROR_CHECK(err_code);
  224. for (;;)
  225. {
  226. m_blocks_transferred = 0;
  227. mp_block_to_fill = NULL;
  228. mp_block_to_check = NULL;
  229. prepare_tx_data(m_buffer_tx[0]);
  230. nrf_drv_i2s_buffers_t const initial_buffers = {
  231. .p_tx_buffer = m_buffer_tx[0],
  232. .p_rx_buffer = m_buffer_rx[0],
  233. };
  234. err_code = nrf_drv_i2s_start(&initial_buffers, I2S_DATA_BLOCK_WORDS, 0);
  235. APP_ERROR_CHECK(err_code);
  236. do {
  237. // Wait for an event.
  238. __WFE();
  239. // Clear the event register.
  240. __SEV();
  241. __WFE();
  242. if (mp_block_to_fill)
  243. {
  244. prepare_tx_data(mp_block_to_fill);
  245. mp_block_to_fill = NULL;
  246. }
  247. if (mp_block_to_check)
  248. {
  249. check_rx_data(mp_block_to_check);
  250. mp_block_to_check = NULL;
  251. }
  252. } while (m_blocks_transferred < BLOCKS_TO_TRANSFER);
  253. nrf_drv_i2s_stop();
  254. NRF_LOG_FLUSH();
  255. bsp_board_leds_off();
  256. nrf_delay_ms(PAUSE_TIME);
  257. }
  258. }
  259. /** @} */