This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MCU SPI Communicate With CC2540 Keyfob

Other Parts Discussed in Thread: CC2540, BLE-STACK, CC2541

Hello to all,

I am currently trying to make my MCU to communicate with the CC2540, and that to receive a value and transmit it.

I have alwready done the SPI communication between the MCU and the CC2540, but as a stand alone.  Meaning the 8051 is working only as an SPI Slave and not as a Bluetooth.

I am using the KeyfobDemo project for CC2540 and I am trying to modify it in order to work.

Does anyone have an idea of where to start with the SPI setup.  I am currently guessing modifying the hal_board_cfg.h and changing the XNV.

Any help will be appreciated.

Thank you in advance,

Georgios

  • Hey Georgios,

    The best example we have to start from is HostTestRelease. There is a SPI (slave) build for that project. It configures the device as a network processor which processes HCI commands from a SPI master. Check out the preprocessor defined symbols and also look through the _hal_uart_spi.c file.

    If you follow HalDriverInit() using the preprocessor defines you should be able to see how the SPI peripheral is configured.

    -Matt

  • Hi there Matt,

    I have used your suggestion and I am trying to modify the HostTestRealease project.  I have read the hal_uart_spi and am trying to modify it according to my PCB.  My question is, when I am done with the setup of the board what should I do to, for example change the Device name and broadcast it?

    Thanx again

  • There are defined serial commands which can be used to control the network processor. Take a look at the TI_BEL_Vendor_Specific_HCI_Guide.pdf located in the Documents folder of your BLE-Stack download. This gives you a listing of all commands that we have defined along with arguments and use cases.

    To see how each of these commands are handled within the code look at hci_ext_app.c and you'll see a few processExMsg...() funcions which handle these commands for each specific BLE layer. I would use these functions and also the simpleBLEperipheral project as starting points to understand which commands you should send for your application.

    -Matt

  • Hello Matt,

    Thank you again for all.  I am still a little bit confused in to what project should I modify.  My main purpose is to make the CC2540 when "told" from the MCU to start advertising and be able to change some parameters.

    1) When the CC2540 starts advertising it normally advertises its serial number as well as its device name?

    2) Is it possible before the device starts advertising its name, eg keyfob, to change the Device name THROUGH the SPI from the MCU?


    3) My final task is to be able for a dongle, which I have from TI, to connect to my Bluetooth and retrieve a value that has been written before using the SPI and the MCU.  For instance I would like the MCU to send a value, something like a value from an ADC, to the CC2540 via SPI and then the CC2540 to store it in a register and then to be able for a dongle to connect to it and retrieve this value.

    Thank you again,

    Georgios

  • Hey Georgios,

    I'm confused about what your system is going to look like. Are you wanting to use the CC2541 as a network processor or are you going to run an application code on the CC2541 that receives data/commands from an another mcu via SPI?

    Either way I'll try to answer the questions below:

    1. You can advertise whatever data you want. If you look at our SimpleBLEPeripheral project in simpleBLEPeripheral.c you'll notice  the vars advertData and scanRspData. The basic structure this app is using for advertising data is  <Length>,<GAP_ADTYPE_DEFINE>,<DATA>. In advertData there are two things being communicated, flags and two service UUIDS. There are a set of other GAP_ADTYPE_DEFINEs you can use that are given in gap.h. If the central device is actively scanning then the scanRspData will also be sent from the peripheral device. In the case of this app it will send it's complete name and connection interval values. You don't have to use this structure for advertising but it is convenient. If you wanted you could advertise gibberish and not use the data in the adv. packet or use some other structure for the data different than what we provided. However if you want to use the data on the central side you will need to know how to correctly interpret the bytes you receive.

    2. It's definitely possible to change the name. In the case of the simpleBLEperipheral scanRspData is just an array of bytes. You can update this array and change the name of the device or even what it is sending but be cognizant of the structure of the adv data fields. You will have to update the device with this new advertising data or scan response data using the GAPRole_SetParameter() function.

    3. To explain this is to explain the better part of the technology which is a tough task for a forum post. If you can give me a more specific question that help me provide a better answer. However, to begin you need to understand the attribute table and services and how the central device can read/write the different fields of the attribute table. Transferring data is using BLE is not as simple as one function call that will give you point to point comms. Look up the profile attributes in simpleGATTprofile.c. Use Btool (provided in the BLE stack) and your dongle to create a connection with another CC254x running simpleBLEperiphal and see how you read/write characteristics.

    -Matt

  • Hello Matt,

    I am sorry to confuse you.  I am planning to "control" the CC2540 from an MCU via SPI.  Maybe this will help:

    I would like for the MCU to send via SPI    "Georgios", and the CC2540 to receive this (using the HCI commands) and change the Device Name, so I can send then the start advertise HCI command in order for it to start advertising and.  And thus the dongle to read after a scan Georgios.  Similarly I want to send another HCI command and change an attribute, so that when the dongle establishes a link and performs a read on that attribute to receive the data that I have sent from the MCU.

    I have changed the name of the device altering the array, even with an external interrupt, but what I would like is if this can be done using the HCI so the name comes from the MCU via SPI.  Also what project should I try to modify for all of this.

    Thanx again,

    Georgios

  • Hey Georgios,

    Sorry about the trouble I understand what you are trying to do now. Using the CC2540 as a network processor and also being a GATT server is more tricky than just using the HCI commands. The HCI commands give you hooks into the BLE API calls so you can use GAP Update Advertising Data to change the name in the data field of the advertising packet. However as a GATT server you must manage the attribute table as well, which is specific to the profiles you are using. This means that there are no HCI commands for interacting with the attributes of your GATT server. 

    In the Host Test Release project only the GAP service is provided in the attribute table. All other services must be added to the project. There are a few solutions to this. You can store your attribute table on the MCU in which case you will receive all GATT R/W requests via SPI on your MCU. You can also implement the profiles/services you need on the network processor and then define your own commands to interact with these profiles (you could create a command that changes the device name for instance). Check out this page here for some more information http://processors.wiki.ti.com/index.php/CC254X_WITH_EXT_MCU

    Hope that is more helpful,

    -Matt

  • Hi there Matt,

    Ok can we start from something simple... just to point out the project for modifing.  Just for a simple MCU - CC2540 Communication via SPI.  Is it safe to use the Host Test Release project (CC2540SPI) or the (CC2540USB)?

    If yes then:

     

    1) I can see in the hal_board_cfg.h that the 

    #if !defined HAL_UART_SPI
    #define HAL_UART_SPI 0
    #endif

    HAL_UART_SPI is 0 if not defined the HAL_UART_SPI.  But I can't find where the HAL_UART_SPI is defined in the first place.  I need to define it in order to understand and alter the _hal_uart_spi.c.  I want the HAL_UART_SPI = 1, So I can use the UART0 Alt pins for my SPI.

    - MISO: P0_2 (PIN9 on Debug Connector P18)

    - MOSI: P0_3 (PIN11 on Debug Connector P18)
    - SSN: P0_4 (PIN13 on Debug Connector P18)
    - SCK: P0_5 (PIN15 on Debug Connector P18)

    Thank you again,

    Georgios

     

  • HAL_UART_SPI should be a preprocessor defined symbol. You can find this if you go to Project->Options->C/C++ Compiler and then Preprocessor tab. If you use the SPI build of HostTestRelease you will see that HAL_UART_SPI=2 is a defined symbol.

    -Matt

  • Hi Matt,

    Thank you for the reply.  I use the SPI build and I found where to change the HAL_UART_SPI.  Now to make it use the _hal_uart_spi.c do I have to go and put these two defined symbols as well, or just by altering the (HAL_UART_SPI=1) is enough for the CC2540 to work with the SPI?

    INT_HEAP_LEN=2700
    HALNODEBUG
    OSAL_CBTIMER_NUM_TASKS=1
    POWER_SAVING
    HAL_AES_DMA=TRUE
    HAL_DMA=TRUE
    HAL_UART=TRUE


    HAL_UART_SPI=TRUE                                  // May be needed
    HAL_SPI_MASTER=FALSE                           // May be needed


    HAL_UART_DMA=0
    HAL_UART_ISR=0
    HAL_UART_SPI=1
    HAL_SPI_QUEUED_TX=TRUE
    HAL_KEY=FALSE
    HAL_LCD=FALSE
    HAL_LED=FALSE

    Also Why when Opening the CC2540SPI build there isn't at least the (HAL_SPI_MASTER=TRUE/FALSE) defined in the Preprocessor tab?

  • The TL;DR version: You don't need either one of those preprocessor defines.

     

    HAL_UART_SPI=1 is enough for the CC2540 to work with SPI (writing TRUE or FALSE will overwrite the assignment I believe). If you define it the symbol at all (no matter what value you define) the preprocessor will include any of the code segments wrapped with an "#if defined HAL_UART_SPI". I know in GCC if you do not define a symbol it defaults to 0 during any of the preprocessor control operators. It's more than likely the same in IAR.  

    The reason HAL_SPI_MASTER=TRUE/FALSE isn't include is because the device is set to be a spi slave by default. If you define the symbol at all (even assigning it false) it will still configure the device as a master since the preprocessor checks are written to see if the symbol is defined (and not checking the assigned value). This way if you don't include the symbol it is a slave and if you do it is a master.

    There some inherent subtleties in preprocessor controls so I would do some googling if you are really interested (most people aren't don't worry :) ).

    -Matt

  • Hi Matt,

    I think we are almost there... ;)

    So I removed both of the commented declarations and it compiled perfectly.  Now as I go line by line in the _hal_uart_spi.c, I fail to see where the UxGCR,UxBAUD are set up.  I can see them when it is a Master, but when a Slave it isn't.

    #if defined HAL_SPI_MASTER

           PxSEL |= HAL_UART_Px_SEL_M; /* SPI-Master peripheral select */
           UxCSR = 0; /* Mode is SPI-Master Mode */
           UxGCR = 15; /* Cfg for the max Rx/Tx baud of 2-MHz */
           UxBAUD = 255;
    #elif !defined HAL_SPI_MASTER
           PxSEL |= HAL_UART_Px_SEL_S; /* SPI-Slave peripheral select */
           UxCSR = CSR_SLAVE; /* Mode is SPI-Slave Mode */
    #endif

     


    Also once this is all done and downloaded on my CC2540, what is your suggestion for sending the first SPI from my MCU to see if all has been done correctly?

    Thanx again,

    Georgios

  • The USART modules sample input signals using SCK directly so as long as you don't use a baud rate over the allowable max (I believe is 4MHz in the data sheet for slave RX + TX) then you should be fine.

    I would test this out with GAP_DeviceInit and then GAP_MakeDiscoverable. This will get the device advertising and it should be easy to detect if you are getting the expected output if you have a sniffer and can see whether or not you are getting advert. packets.

    -Matt

  • Hi Matt,

    I am trying to download the project with only the changes that you have suggested and the IAR first Error is concerning the Linker:

    "Error[e16]: Segment ISTACK (size: 0xc0 align: 0) is too long for segment definition. At least 0xd more bytes needed. The problem occurred while processing the segment 

    placement command "-Z(IDATA)ISTACK+_IDATA_STACK_SIZE#08-_IDATA_END", where at the moment of placement the available memory ranges were "IDATA:4d-ff" 

    From Forum posts I found a way to overcome it, but I don't know if it is the right way, by changing from

    Project->Options->General Options->Number of virtual Registers from 16 to 8.

    This way the Linker Error went away and I could download the program.  Then all kinds of warnings came out and when I tried to debug it the following screen came on.

    Now from the MCU part.  I am sending via SPI @ 2MHz, I can confirm this from my Oscilloscope, the following as you suggested:

    unsigned char GAP_DeviceInit[]={0x01, // Command
    0x00,0xfe, // OpCode
    0x26, // Length
    0x04, // profileRole
    0x03, // maxScanResponses
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // IRK
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // CSRK
    0x01,0x00,0x00,0x00 // signCounter
    };


    unsigned char GAP_MakeDiscoverable[]={0x01, // Command
    0x06,0xfe, // OpCode
    0x0a, // Length
    0x00, // eventType
    0x00, // initiatorAddrType
    0x00,0x00,0x00,0x00,0x00,0x00, // initiatorAddr
    0x07, // channelMap
    0x00 // filterPolicy
    };

    The return that I receive is all 0x00.  for the GAP_DeviceInit as well as from GAP_MakeDiscoverable.  Is this what I should I expect, because after I have sent them, the device isn't discover-able from my dongle.

    Thank you again, 

    Georgios.

  • Are you using IAR EW 8.30? I would go back to 8.20 because it will make life generally easier when developing with this device even though it is a bit of a pain up front. The older versions can be found here http://www.iar.com/Products/Wireless-solutions/Tools-for-TI-wireless/.

    As far as the commands go they could be dependent on the linker and flashing errors. Can you run the device in debug mode and put a breakpoint in processExtMsg() in hci_ext_app.c and see what the rx'ed packet looks like?

    -Matt

  • Hi Matt,

    I am trying to install now the 8.20.  As far as for the command.  Is the commands right? Because I found them in the forum, but they don't comply with the structure in _hal_uart_spi.c file:

    <SOF> <LEN> <DATA Byte 1> < DATA Byte2 >...<DATA Byte N> <FCS>

    I will be able to test them once I have successfully installed the 8.2, but in the meanwhile I want to know that the commands that I am sending are correct in order to rule out that part if it doesn't work.

    Thank you again,

    Georigos

  • Hey Georgios,

    Check out the vendor specific HCI guide in the documents folder of the BLE stack download. It defines the HCI command structure. The command packet is defined as follows:

    There is also a leading byte with the value one to define the HCI packet as a command packet so what you sent looks correct with respect to the HCI guide.

    -Matt

  • Hey Matt,

    I'm doing something similar to Georgios and am at roughly the same spot in my development cycle. Regarding the commands he posted above, I understand the HCI commands, but do those need to be wrapped up as the "data" segment of the defined SPI protocol?

    E.g. <SOF (0xFE)><LEN><HCI-COMMAND-PACKET><FCS (Frame Check Sequence)>
  • Hey Michael, 

    You're correct, <1B SOF><1B LEN><N-Bytes HCI Command><1B FCS>, is the SPI frame you will use. The FCS is calculated by XOR'ing all bytes in the HCI command and the length byte. 

    -Matt