It's worth noting that CP/M was written originally in the PL/M-80 programming language (also developed by Gary Kildall) (source here )
The PL/M-80 Manual on page 11 states that
The character set used in PL/M is a subset of both ASCII and EBCDIC character sets. The valid PL/M characters consist of the alphanumerics
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h I j k l m n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9
along with the special characters
= . / ( ) + - ' * , < > : ;
and the blank characters
space tab carriage-return line-feed
If a PL/M program contains any character not in this set, the compiler may treat the character as an error
That's 80 characters.
Interestingly there is no mention there of $ at all - yet on page 15 it is listed as a character that "may be freely inserted between the characters of a constant to improve readability".
I can't say whether or why this might have affected the decision to use $ as the string terminator for function 15 in CP/M, especially since page 16 is explicit that "character strings are denoted by printable ascii characters enclosed by apostrophes" which doesn't limit it to the same character set as the code body.
I can say from personal experience that function 15 was almost never used, and CP/M / CP/M-86 / MP/M / Concurrent DOS / CDOS /… assembler programmers pretty well invariably used subroutines containing loops that called function 2, usually using either a byte count or a null terminator.